Collect reference hierarchy for SCL values 85/1285/1
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 4 Dec 2017 12:20:31 +0000 (14:20 +0200)
committerHannu Niemistö <hannu.niemisto@semantum.fi>
Mon, 4 Dec 2017 12:20:31 +0000 (14:20 +0200)
refs #7662

Change-Id: I4bf296f8c676fdc5c3387d496a898a364ca78a7b

14 files changed:
bundles/org.simantics.scl.compiler/META-INF/MANIFEST.MF
bundles/org.simantics.scl.compiler/scl/SCL/CallHierarchy.scl [new file with mode: 0644]
bundles/org.simantics.scl.compiler/scl/SCL/Reflection.scl
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/CompilationContext.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/SCLCompiler.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/contexts/TranslationContext.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/Module.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/ModuleDebugInfo.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/SymbolReference.java [new file with mode: 0644]
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/options/ModuleCompilationOptions.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java

index 7f76ebc102a775b01eba28a73ea0e300332e430d..c36c46274f65fffe96cc713c16f82c595b0455ad 100644 (file)
@@ -63,6 +63,7 @@ Export-Package: org.cojen.classfile,
  org.simantics.scl.compiler.markdown.nodes,
  org.simantics.scl.compiler.module,
  org.simantics.scl.compiler.module.coverage,
+ org.simantics.scl.compiler.module.debug,
  org.simantics.scl.compiler.module.options,
  org.simantics.scl.compiler.module.repository,
  org.simantics.scl.compiler.runtime,
diff --git a/bundles/org.simantics.scl.compiler/scl/SCL/CallHierarchy.scl b/bundles/org.simantics.scl.compiler/scl/SCL/CallHierarchy.scl
new file mode 100644 (file)
index 0000000..5ab8e81
--- /dev/null
@@ -0,0 +1,49 @@
+module {
+    features = [edo],
+    export = [whoCalls, unusedDefinitions]
+}
+
+import "SCL/Reflection"
+
+@JavaType "org.simantics.scl.compiler.module.debug.SymbolReference"
+data SymbolReference =
+    @JavaType "org.simantics.scl.compiler.module.debug.SymbolReference"
+    @FieldNames [referred, referrer, referenceLocation]
+    SymbolReference {referred :: Name, referrer :: String, referenceLocation :: Location}
+
+importJava "org.simantics.scl.compiler.module.debug.ModuleDebugInfo" where
+    data ModuleDebugInfo
+    
+    symbolReferences :: ModuleDebugInfo -> [SymbolReference]
+
+importJava "org.simantics.scl.compiler.module.Module" where
+    @JavaName "getModuleDebugInfo"
+    
+    debugInfo :: Module -> Maybe ModuleDebugInfo
+    
+whoCalls :: String -> String -> <Proc> [(String, String, Long)]
+whoCalls moduleName valueName = 
+    [ (callerModuleName, referrer, referenceLocation)
+    | callerModuleName <- sclModuleNames
+    , Just callerModule = moduleByName callerModuleName
+    , Just debugInfo = debugInfo callerModule
+    , SymbolReference {referred, referrer, referenceLocation} <- symbolReferences debugInfo
+    , referred == name
+    ]
+  where
+    name = createName moduleName valueName
+    
+unusedDefinitions :: <Proc> [Name]
+unusedDefinitions =
+    [ createName moduleName def
+    | moduleName <- sclModuleNames
+    , Just module = moduleByName moduleName
+    , def <- valueNamesOf module
+    ]
+    \\ 
+    [ referred
+    | callerModuleName <- sclModuleNames
+    , Just callerModule = moduleByName callerModuleName
+    , Just debugInfo = debugInfo callerModule
+    , SymbolReference {referred} <- symbolReferences debugInfo
+    ]
\ No newline at end of file
index cf8b88eeac1aa42ded978b60a4b6cd77d735d98a..e32401d502c79aada0291d3c510b91a28b0ffc14 100644 (file)
@@ -1,5 +1,6 @@
 module {
-    export = [possibleUnsafeSclValueByName, unsafeSclValueByName, sclModuleNames]
+    export = [possibleUnsafeSclValueByName, unsafeSclValueByName, sclModuleNames, moduleByName,
+              moduleOf, nameOf, createName, valueNamesOf]
 }
 
 include "SCL/ReflectionJava"
@@ -11,11 +12,47 @@ importJava "org.simantics.scl.compiler.module.repository.ModuleRepository" where
     @JavaName getSourceRepository
     moduleSourceRepositoryOf :: ModuleRepository -> ModuleSourceRepository
     
+    @JavaName getModule
+    moduleByName_ :: ModuleRepository -> String -> <Proc> Failable Module 
+    
 importJava "org.simantics.scl.compiler.source.repository.ModuleSourceRepository" where
     data ModuleSourceRepository
     
     @JavaName getModuleNames
     sclModuleNames_ :: ModuleSourceRepository -> [String]
+
+importJava "org.simantics.scl.compiler.errors.Failable" where
+    data Failable a
+    
+    didSucceed :: Failable a -> Boolean
+    getResult :: Failable a -> Maybe a 
+
+importJava "org.simantics.scl.compiler.module.Module" where
+    data Module
+    
+    @JavaName getValueNames
+    valueNamesOf_ :: Module -> [String]    
+    
+importJava "org.simantics.scl.compiler.common.names.Name" where
+    data Name
+    
+    @JavaName module
+    moduleOf_ :: Name -> String
+    @JavaName name
+    nameOf_ :: Name -> String
+    
+    @JavaName create
+    createName_ :: String -> String -> Name
+
+instance Show Name where
+    sb <+ n = sb << moduleOf n << "/" << nameOf n
+    
+moduleOf = moduleOf_
+nameOf = nameOf_
+createName = createName_
+valueNamesOf = valueNamesOf_      
+    
+type Location = Long
     
 unsafeSclValueByName :: String -> <Proc> a
 unsafeSclValueByName = unsafeSclValueByName_ MODULE_REPOSITORY
@@ -25,3 +62,8 @@ possibleUnsafeSclValueByName name = Just (unsafeSclValueByName name) `catch` \(_
 
 sclModuleNames :: <Proc> [String]
 sclModuleNames = sclModuleNames_ (moduleSourceRepositoryOf MODULE_REPOSITORY)
+
+moduleByName :: String -> <Proc> Maybe Module
+moduleByName name = getResult failable
+  where
+    failable = moduleByName_ MODULE_REPOSITORY name
\ No newline at end of file
index b9625af78c5817621bb8f68245e6179f5336ea02..bd6546dacfe05abc4bd52643a203087a90b5b48b 100644 (file)
@@ -13,6 +13,7 @@ import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
 import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
 import org.simantics.scl.compiler.internal.header.ModuleHeader;
 import org.simantics.scl.compiler.module.ConcreteModule;
+import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
 import org.simantics.scl.compiler.types.Type;
 
@@ -26,6 +27,7 @@ public class CompilationContext implements EnvironmentalContext {
     public JavaNamingPolicy namingPolicy;
     public ConcreteModule module;
     public ModuleHeader header;
+    public ModuleDebugInfo moduleDebugInfo;
     
     private THashMap<Name, SCLValue> valueCache = new THashMap<Name, SCLValue>();
 
index 799b0726819f3d6704f982ebfa0723e20fceb7e9..ee21ef641a645ea5eae7096f62ece738fa6957fb 100644 (file)
@@ -106,8 +106,10 @@ import org.simantics.scl.compiler.module.ConcreteModule;
 import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.InvalidModulePathException;
 import org.simantics.scl.compiler.module.ModuleUtils;
+import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
 import org.simantics.scl.compiler.module.repository.ImportFailure;
 import org.simantics.scl.compiler.module.repository.ImportFailureException;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.compiler.types.TForAll;
 import org.simantics.scl.compiler.types.TFun;
@@ -1077,7 +1079,7 @@ public class Elaboration {
         
         final THashMap<SectionName, Query[]> sections = new THashMap<SectionName, Query[]>();
 
-        final TranslationContext context = createTranslationContext();
+        final TranslationContext context = createTranslationContext(ruleName);
         if(length > 0) {
             THashMap<String, Variable> variables = context.getVariables();
             for(TransformationRule extendsRule : extendsRules) {
@@ -1228,7 +1230,7 @@ public class Elaboration {
                 continue;
             try {
                 SCLValue value = module.getValue(name);
-                TranslationContext context = createTranslationContext();
+                TranslationContext context = createTranslationContext(name);
                 Expression expression = context.translateCases2(defs);
                 value.setExpression(expression);
                 
@@ -1245,7 +1247,7 @@ public class Elaboration {
                 continue;
             try {
                 SCLValue value = module.getValue(name);
-                TranslationContext context = createTranslationContext();
+                TranslationContext context = createTranslationContext(name);
                 Expression expression = context.translateCases2(defs);
                 value.setExpression(expression);
                 
@@ -1279,13 +1281,13 @@ public class Elaboration {
             DRelationAst definition = definitions.get(0);
             ConcreteRelation relation = (ConcreteRelation)module.getRelation(name);
             relation.location = definition.location;
-            TranslationContext context = createTranslationContext();
+            TranslationContext context = createTranslationContext(name);
             definition.translateTo(context, relation);
         }
     }
     
-    private TranslationContext createTranslationContext() {
-        return new TranslationContext(compilationContext, null);
+    private TranslationContext createTranslationContext(String definitionName) {
+        return new TranslationContext(compilationContext, null, definitionName);
     }
     
     private void handleAnnotation(SCLValue value, ArrayList<DValueAst> defs, DAnnotationAst annotation) {
@@ -1367,4 +1369,8 @@ public class Elaboration {
             branchPoints.put(valueName, injector.getAndClearBranchPoints());
         }
     }
+
+    public void collectDebugInfo() {
+        module.moduleDebugInfo = compilationContext.moduleDebugInfo = new ModuleDebugInfo();
+    }
 }
index cd43b76e15dec63e81b6ca704238ee2f956aec4c..0da48676ad0088cda95db8c4a5a53ae5942be191 100644 (file)
@@ -82,6 +82,8 @@ public class SCLCompiler {
                     declarations.relationDefinitionsAst);
             if(options.computeCoverage)
                 elaboration.addCoverageBranchPoints();
+            if(options.collectDebugInfo)
+                elaboration.collectDebugInfo();
             // Elaboration
             if(hasErrors()) return;
             elaboration.addTypesToEnvironment(
index aeeb4cb5525b3be9f02bfb5cfee4e92fc857b8cb..b71c0ad276e69937fbde4d6be0969954b3dd151d 100644 (file)
@@ -4,7 +4,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 
 import org.simantics.scl.compiler.common.names.Name;
-import org.simantics.scl.compiler.common.names.Names;
 import org.simantics.scl.compiler.common.precedence.Associativity;
 import org.simantics.scl.compiler.common.precedence.Precedence;
 import org.simantics.scl.compiler.compilation.CompilationContext;
@@ -33,6 +32,8 @@ import org.simantics.scl.compiler.environment.Namespace;
 import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
 import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
+import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
+import org.simantics.scl.compiler.module.debug.SymbolReference;
 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
 import org.simantics.scl.compiler.types.Type;
 
@@ -77,6 +78,10 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
     
     public CHRRuleset currentRuleset;
     
+    public ModuleDebugInfo moduleDebugInfo;
+    
+    private String definitionName;
+    
     static class Entry {
         String name;
         Variable variable;
@@ -104,9 +109,11 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
         }
     }
     
-    public TranslationContext(CompilationContext compilationContext, LocalEnvironment localEnvironment) {
+    public TranslationContext(CompilationContext compilationContext, LocalEnvironment localEnvironment, String definitionName) {
         super(compilationContext);
         this.localEnvironment = localEnvironment;
+        this.moduleDebugInfo = compilationContext.moduleDebugInfo;
+        this.definitionName = definitionName;
     }
     
     public static boolean isConstructorName(String name) {
@@ -193,6 +200,8 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
             String deprecatedDescription = value.isDeprecated();
             if(deprecatedDescription != null)
                 errorLog.logWarning(location, "Deprecated value " + value.getName().name + "." + (deprecatedDescription.isEmpty() ? "" : " " + deprecatedDescription));
+            if(moduleDebugInfo != null)
+                moduleDebugInfo.symbolReferences.add(new SymbolReference(value.getName(), definitionName, location));
             return new EConstant(location, value);
         } catch (AmbiguousNameException e) {
             if(SCLCompilerConfiguration.ALLOW_OVERLOADING)
@@ -219,6 +228,8 @@ public class TranslationContext extends TypeTranslationContext implements Enviro
                 public Expression realize() {
                     EConstant expression = new EConstant(altValue);
                     expression.location = location;
+                    if(moduleDebugInfo != null)
+                        moduleDebugInfo.symbolReferences.add(new SymbolReference(altValue.getName(), definitionName, location));
                     return expression;
                 }
 
index e52420925ea4763b332361633ad05a8565f5a44e..8a83e5f35644631bdc58c568dd70c275a264109d 100644 (file)
@@ -5,7 +5,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.SynchronousQueue;
 import java.util.function.Consumer;
 
 import org.simantics.scl.compiler.common.names.Name;
@@ -23,6 +22,7 @@ import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
 import org.simantics.scl.compiler.environment.filter.NamespaceFilter;
 import org.simantics.scl.compiler.errors.CompilationError;
 import org.simantics.scl.compiler.internal.codegen.effects.EffectConstructor;
+import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
 import org.simantics.scl.compiler.top.ModuleInitializer;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.runtime.profiling.BranchPoint;
@@ -55,6 +55,8 @@ public class ConcreteModule implements Module {
     ModuleInitializer moduleInitializer;
 
     protected Documentation documentation;
+    
+    public ModuleDebugInfo moduleDebugInfo;
 
     public ConcreteModule(String moduleName) {
         this.moduleName = moduleName;
@@ -270,6 +272,11 @@ public class ConcreteModule implements Module {
                 consumer.accept(value);
         });
     }
+    
+    @Override
+    public List<String> getValueNames() {
+        return new ArrayList<String>(values.keySet());
+    }
 
     public Collection<SCLRelation> getRelations() {
         return relations.values();
@@ -337,4 +344,9 @@ public class ConcreteModule implements Module {
     public void setDeprecation(String deprecation) {
         this.deprecation = deprecation;
     }
+    
+    @Override
+    public ModuleDebugInfo getModuleDebugInfo() {
+        return moduleDebugInfo;
+    }
 }
index 6e6690fef173b17e11422bb7c79e0148104648ac..0ea33cb463f2de07a56c5ece742187cfa43b7c1c 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.scl.compiler.module;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
@@ -15,9 +16,11 @@ import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
 import org.simantics.scl.compiler.elaboration.rules.MappingRelation;
 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
+import org.simantics.scl.compiler.environment.filter.AcceptAllNamespaceFilter;
 import org.simantics.scl.compiler.environment.filter.NamespaceFilter;
 import org.simantics.scl.compiler.errors.CompilationError;
 import org.simantics.scl.compiler.internal.codegen.effects.EffectConstructor;
+import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
 import org.simantics.scl.compiler.top.ModuleInitializer;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.runtime.profiling.BranchPoint;
@@ -30,6 +33,13 @@ public interface Module {
     String getDefaultLocalName();
     
     SCLValue getValue(String name);
+    default List<String> getValueNames() {
+        ArrayList<String> valueNames = new ArrayList<String>();
+        findValuesForPrefix("", AcceptAllNamespaceFilter.INSTANCE, value -> {
+            valueNames.add(value.getName().name);
+        });
+        return valueNames;
+    }
     List<Constant> getFieldAccessors(String name);
     SCLRelation getRelation(String name);
     SCLEntityType getEntityType(String name);
@@ -61,4 +71,11 @@ public interface Module {
     CompilationError[] getWarnings();
     ClassLoader getParentClassLoader();
     String getDeprecation();
+    
+    /**
+     * May return null, if there is no debug info.
+     */
+    default ModuleDebugInfo getModuleDebugInfo() {
+        return null;
+    }
 }
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/ModuleDebugInfo.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/ModuleDebugInfo.java
new file mode 100644 (file)
index 0000000..a40daac
--- /dev/null
@@ -0,0 +1,7 @@
+package org.simantics.scl.compiler.module.debug;
+
+import java.util.ArrayList;
+
+public class ModuleDebugInfo {
+    public final ArrayList<SymbolReference> symbolReferences = new ArrayList<SymbolReference>(); 
+}
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/SymbolReference.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/debug/SymbolReference.java
new file mode 100644 (file)
index 0000000..a2bea8c
--- /dev/null
@@ -0,0 +1,15 @@
+package org.simantics.scl.compiler.module.debug;
+
+import org.simantics.scl.compiler.common.names.Name;
+
+public class SymbolReference {
+    public final Name referred;
+    public final String referrer;
+    public final long referenceLocation;
+
+    public SymbolReference(Name referred, String referrer, long referenceLocation) {
+        this.referred = referred;
+        this.referrer = referrer;
+        this.referenceLocation = referenceLocation;
+    }
+}
index 41c5f776314b9a948bcba47ddd119318a8f82f15..90c9806cac02f94cb09b3ac483b743705777c5e2 100644 (file)
@@ -10,6 +10,7 @@ public class ModuleCompilationOptions {
     
     public boolean computeCoverage;
     public boolean silent = false;
+    public boolean collectDebugInfo = false;
 
     public ModuleCompilationOptions(boolean computeCoverage) {
         this.computeCoverage = computeCoverage;
index 899ee0418efef4af964fa01d69ddf06edfcb6520..36994d136533435522642855fdf5a8817203fd57 100644 (file)
@@ -269,7 +269,7 @@ public class ExpressionEvaluator {
         
         // Elaboration
         {
-            TranslationContext context = new TranslationContext(compilationContext, localEnvironment);
+            TranslationContext context = new TranslationContext(compilationContext, localEnvironment, "expression");
             expression = expression.resolve(context);
             if(!errorLog.hasNoErrors())
                 throw new SCLExpressionCompilationException(errorLog.getErrors());
index 59f8e5fd804616a59ac705a31563160404206f92..e6bddee7e3c9ca9bf4ac140d93db5999573718e4 100644 (file)
@@ -2,9 +2,12 @@ package org.simantics.scl.osgi;
 
 import java.util.ArrayList;
 
+import org.eclipse.core.internal.runtime.PlatformActivator;
 import org.simantics.scl.compiler.errors.DoesNotExist;
 import org.simantics.scl.compiler.errors.Failable;
 import org.simantics.scl.compiler.module.Module;
+import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
+import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
 import org.simantics.scl.compiler.source.repository.ModuleSourceRepository;
 import org.simantics.scl.compiler.testing.repository.TestRepository;
@@ -23,6 +26,19 @@ public class SCLOsgi {
     public static ModuleRepository MODULE_REPOSITORY = new ModuleRepository(SOURCE_REPOSITORY);
     public static TestRepository TEST_REPOSITORY = new ServiceBasedTestRepository(Activator.getContext());
 
+    static {
+        MODULE_REPOSITORY.setAdvisor(new ModuleCompilationOptionsAdvisor() {
+            ModuleCompilationOptions options = null;
+            @Override
+            public ModuleCompilationOptions getOptions(String moduleName) {
+                if(options == null) {
+                    options = new ModuleCompilationOptions(false);
+                    options.collectDebugInfo = Activator.getContext().getProperty("osgi.dev") != null; //$NON-NLS-1$
+                }
+                return options; 
+            }
+        });
+    }
     
     public static String compileAllModules() {
         ArrayList<String> modulesWithErrors = new ArrayList<String>();