You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by sr...@apache.org on 2018/09/30 15:25:36 UTC

[incubator-netbeans] branch master updated: [NETBEANS-1293] First stab at flow typing, tests show use cases implemented

This is an automated email from the ASF dual-hosted git repository.

sreimers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 59dd171  [NETBEANS-1293] First stab at flow typing, tests show use cases implemented
59dd171 is described below

commit 59dd171b097cd680680b0cf17321bf6a021e222a
Author: Sven Reimers <sv...@users.noreply.github.com>
AuthorDate: Sun Sep 30 17:25:31 2018 +0200

    [NETBEANS-1293] First stab at flow typing, tests show use cases implemented
---
 .../modules/groovy/editor/api/FindTypeUtils.java   |  10 +-
 .../groovy/editor/api/parser/GroovyParser.java     |  22 ++--
 .../completion/inference/GroovyTypeAnalyzer.java   |   4 +-
 .../completion/inference/MethodInference.java      | 136 +++++++++++++++++++--
 .../completion/inference/TypeInferenceVisitor.java |  86 ++++++++++++-
 .../completion/provider/MetaElementsProvider.java  |  44 ++++++-
 .../groovy/editor/occurrences/TypeVisitor.java     |   4 +
 .../CompletionReturnType1.groovy                   |  33 +++++
 ...1.groovy.testCompletionReturnType1_1.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_2.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_3.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_4.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_5.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_6.completion |  29 +++++
 ...1.groovy.testCompletionReturnType1_7.completion |  29 +++++
 .../groovy/editor/api/completion/FlowCCTest.java   |  64 ++++++++++
 16 files changed, 574 insertions(+), 32 deletions(-)

diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/FindTypeUtils.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/FindTypeUtils.java
index 328ba36..8ecf2ac 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/FindTypeUtils.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/FindTypeUtils.java
@@ -397,10 +397,12 @@ public final class FindTypeUtils {
     }
 
     private static OffsetRange getAnnotationRange(AnnotationNode annotation, BaseDocument doc, int cursorOffset) {
-        final int offset = ASTUtils.getOffset(doc, annotation.getLineNumber(), annotation.getColumnNumber());
-        final OffsetRange range = ASTUtils.getNextIdentifierByName(doc, annotation.getClassNode().getNameWithoutPackage(), offset);
-        if (range.containsInclusive(cursorOffset)) {
-            return range;
+        if (annotation.getLineNumber() != -1) {
+            final int offset = ASTUtils.getOffset(doc, annotation.getLineNumber(), annotation.getColumnNumber());
+            final OffsetRange range = ASTUtils.getNextIdentifierByName(doc, annotation.getClassNode().getNameWithoutPackage(), offset);
+            if (range.containsInclusive(cursorOffset)) {
+                return range;
+            }
         }
         return OffsetRange.NONE;
     }
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
index 6b4306c..f5ca9c2 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/api/parser/GroovyParser.java
@@ -33,11 +33,16 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.swing.event.ChangeListener;
 import javax.swing.text.BadLocationException;
+import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CompileUnit;
 import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.CompilerConfiguration;
 import org.codehaus.groovy.control.ErrorCollector;
 import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.messages.Message;
 import org.codehaus.groovy.control.messages.SimpleMessage;
 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
@@ -418,12 +423,13 @@ public class GroovyParser extends Parser {
         ClassPath bootPath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.BOOT);
         ClassPath compilePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.COMPILE);
         ClassPath sourcePath = fo == null ? ClassPath.EMPTY : ClassPath.getClassPath(fo, ClassPath.SOURCE);
-        ClassPath cp = ClassPathSupport.createProxyClassPath(bootPath, compilePath, sourcePath);
+        ClassPath transformPath = ClassPathSupport.createProxyClassPath(bootPath, compilePath);
+        ClassPath cp = ClassPathSupport.createProxyClassPath(transformPath, sourcePath);
 
         CompilerConfiguration configuration = new CompilerConfiguration();
         final ClassNodeCache classNodeCache = ClassNodeCache.get();
         final GroovyClassLoader classLoader = classNodeCache.createResolveLoader(cp, configuration);
-        final GroovyClassLoader transformationLoader = classNodeCache.createTransformationLoader(cp,configuration);        
+        final GroovyClassLoader transformationLoader = classNodeCache.createTransformationLoader(transformPath, configuration);
         ClasspathInfo cpInfo = ClasspathInfo.create(
                 // we should try to load everything by javac instead of classloader,
                 // but for now it is faster to use javac only for sources - not true
@@ -475,13 +481,15 @@ public class GroovyParser extends Parser {
 
                     int line = se.getStartLine();
 
-                    if(line < 1 )
+                    if (line < 1) {
                         line = 1;
+                    }
 
                     int col = se.getStartColumn();
 
-                    if(col < 1 )
+                    if (col < 1) {
                         col = 1;
+                    }
 
                     // display Exception information
 //                    LOG.log(Level.FINEST, "-----------------------------------------------");
@@ -633,9 +641,9 @@ public class GroovyParser extends Parser {
             displayName = description;
         }
 
-        Error error =
-            new GroovyError(key, displayName, description, context.snapshot.getSource().getFileObject(),
-                startOffset, endOffset, severity, CompilerErrorResolver.getId(description));
+        Error error
+                = new GroovyError(key, displayName, description, context.snapshot.getSource().getFileObject(),
+                        startOffset, endOffset, severity, CompilerErrorResolver.getId(description));
 
         context.errorHandler.error(error);
 
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/GroovyTypeAnalyzer.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/GroovyTypeAnalyzer.java
index 8dc132f..0822fb5 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/GroovyTypeAnalyzer.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/GroovyTypeAnalyzer.java
@@ -20,10 +20,12 @@
 package org.netbeans.modules.groovy.editor.completion.inference;
 
 import java.util.Collections;
+import java.util.ListIterator;
 import java.util.Set;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.netbeans.editor.BaseDocument;
@@ -55,7 +57,7 @@ public class GroovyTypeAnalyzer {
         }
         
         if (caller instanceof MethodCallExpression) {
-            return Collections.singleton(MethodInference.findCallerType(caller));
+            return Collections.singleton(MethodInference.findCallerType(caller, path, document, astOffset));
         }
         
         return Collections.emptySet();
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/MethodInference.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/MethodInference.java
index 12779e2..1ee0e8d 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/MethodInference.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/MethodInference.java
@@ -19,15 +19,27 @@
 
 package org.netbeans.modules.groovy.editor.completion.inference;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.netbeans.api.annotations.common.CheckForNull;
 import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.modules.groovy.editor.api.ASTUtils;
+import org.netbeans.modules.groovy.editor.api.AstPath;
 
 /**
  *
@@ -50,24 +62,38 @@ public final class MethodInference {
      * @return class type of the caller if found, {@code null} otherwise
      */
     @CheckForNull
-    public static ClassNode findCallerType(@NonNull ASTNode expression) {
+    public static ClassNode findCallerType(@NonNull ASTNode expression, @NonNull AstPath path, BaseDocument baseDocument, int offset) {
         // In case if the method call is chained with another method call
         // For example: someInteger.toString().^
         if (expression instanceof MethodCallExpression) {
             MethodCallExpression methodCall = (MethodCallExpression) expression;
-            
-            ClassNode callerType = findCallerType(methodCall.getObjectExpression());
+
+            ClassNode callerType = findCallerType(methodCall.getObjectExpression(), path, baseDocument, offset);
             if (callerType != null) {
-                return findReturnTypeFor(callerType, methodCall.getMethodAsString(), methodCall.getArguments());
+                return findReturnTypeFor(callerType, methodCall.getMethodAsString(), methodCall.getArguments(), path, false, baseDocument, offset);
             }
         }
 
         // In case if the method call is directly on a variable
         if (expression instanceof VariableExpression) {
-            Variable variable = ((VariableExpression) expression).getAccessedVariable();
-            if (variable != null) {
-                return variable.getType();
+            int newOffset = ASTUtils.getOffset(baseDocument, expression.getLineNumber(), expression.getColumnNumber());
+            AstPath newPath = new AstPath(path.root(), newOffset, baseDocument);
+            TypeInferenceVisitor tiv = new TypeInferenceVisitor(((ModuleNode)path.root()).getContext(), newPath, baseDocument, newOffset);
+            tiv.collect();
+            return tiv.getGuessedType();
+
             }
+        if (expression instanceof ConstantExpression) {
+            return ((ConstantExpression) expression).getType();
+        }
+        if (expression instanceof ClassExpression) {
+            return ClassHelper.make(((ClassExpression) expression).getType().getName());
+        }
+
+        if (expression instanceof StaticMethodCallExpression) {
+            StaticMethodCallExpression staticMethodCall = (StaticMethodCallExpression) expression;
+
+            return findReturnTypeFor(staticMethodCall.getOwnerType(), staticMethodCall.getMethod(), staticMethodCall.getArguments(), path, true, baseDocument, offset);
         }
         return null;
     }
@@ -76,12 +102,100 @@ public final class MethodInference {
     private static ClassNode findReturnTypeFor(
             @NonNull ClassNode callerType, 
             @NonNull String methodName,
-            @NonNull Expression arguments) {
-        
-        MethodNode possibleMethod = callerType.tryFindPossibleMethod(methodName, arguments);
+            @NonNull Expression arguments,
+            @NonNull AstPath path,
+            @NonNull boolean isStatic,
+            @NonNull BaseDocument baseDocument,
+            @NonNull int offset
+            ) {
+
+        List<ClassNode> paramTypes = new ArrayList<>();
+        if (arguments instanceof ArgumentListExpression) {
+            ArgumentListExpression argExpression = (ArgumentListExpression) arguments;
+            for (Expression e : argExpression.getExpressions()) {
+                if (e instanceof VariableExpression) {
+                    ModuleNode moduleNode = (ModuleNode) path.root();
+                    int newOffset = ASTUtils.getOffset(baseDocument, e.getLineNumber(), e.getColumnNumber());
+                    AstPath newPath = new AstPath(moduleNode, newOffset, baseDocument);
+                    TypeInferenceVisitor tiv = new TypeInferenceVisitor(moduleNode.getContext(), newPath, baseDocument, newOffset);
+                    tiv.collect();
+                    ClassNode guessedType = tiv.getGuessedType();
+                    if (null == guessedType) {
+                        System.out.println("Bad guessed type");
+                    } else {
+                        paramTypes.add(tiv.getGuessedType());
+                    }
+                } else if(e instanceof ConstantExpression) {
+                    paramTypes.add(((ConstantExpression)e).getType());
+                } else if (e instanceof MethodCallExpression) {
+                    paramTypes.add(findCallerType(e, path, baseDocument, offset));
+                } else if (e instanceof BinaryExpression) {
+                    BinaryExpression binExpression = (BinaryExpression) e;
+                    paramTypes.add(binExpression.getType());
+                } else if (e instanceof ClassExpression) {
+                    ClassExpression classExpression = (ClassExpression) e;
+                    // This should be Class<classExpression.getType()>
+                    paramTypes.add(GenericsUtils.makeClassSafeWithGenerics(Class.class, classExpression.getType()));
+                } else {
+                    System.out.println(e.getClass());
+                }
+            }
+        }
+
+        MethodNode possibleMethod = tryFindPossibleMethod(callerType, methodName, paramTypes, isStatic);
         if (possibleMethod != null) {
             return possibleMethod.getReturnType();
         }
         return null;
     }
+
+    private static MethodNode tryFindPossibleMethod(ClassNode callerType, String methodName, List<ClassNode> paramTypes, boolean isStatic) {
+        int count = paramTypes.size();
+
+        MethodNode res = null;
+        ClassNode node = callerType;
+        do {
+            for (MethodNode method : node.getMethods(methodName)) {
+                if (isStatic && !method.isStatic()) {
+                    continue;
+                }
+                if (method.getParameters().length == count) {
+                    boolean match = true;
+                    for (int i = 0; i != count; ++i) {
+                        if (!paramTypes.get(i).isDerivedFrom(method.getParameters()[i].getType())) {
+                            match = false;
+                            break;
+                        }
+                    }
+
+                    if (match) {
+                        if (res == null) {
+                            res = method;
+                        } else {
+                            if (res.getParameters().length != count) {
+                                return null;
+                            }
+                            if (node.equals(callerType)) {
+                                return null;
+                            }
+
+                            match = true;
+                            for (int i = 0; i != count; ++i) {
+                                if (!res.getParameters()[i].getType().equals(method.getParameters()[i].getType())) {
+                                    match = false;
+                                    break;
+                                }
+                            }
+                            if (!match) {
+                                return null;
+                            }
+                        }
+                    }
+                }
+            }
+            node = node.getSuperClass();
+        } while (node != null);
+
+        return res;
+    }
 }
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/TypeInferenceVisitor.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/TypeInferenceVisitor.java
index 8b8836d..bc69621 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/TypeInferenceVisitor.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/inference/TypeInferenceVisitor.java
@@ -20,17 +20,25 @@
 package org.netbeans.modules.groovy.editor.completion.inference;
 
 import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
 import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.syntax.Types;
 import org.netbeans.editor.BaseDocument;
+import org.netbeans.modules.groovy.editor.api.ASTUtils;
 import org.netbeans.modules.groovy.editor.api.AstPath;
 import org.netbeans.modules.groovy.editor.occurrences.TypeVisitor;
 
@@ -79,11 +87,72 @@ public class TypeInferenceVisitor extends TypeVisitor {
         }
     }
 
+    public void visitField(FieldNode node) {
+        if (sameVariableName(leaf, node)) {
+            if (node.hasInitialExpression()){
+                Expression expression = node.getInitialExpression();
+                if (expression instanceof ConstantExpression
+                        && !expression.getText().equals("null")) { // NOI18N
+                    guessedType = ((ConstantExpression) expression).getType();
+                } else if (expression instanceof ConstructorCallExpression) {
+                    guessedType = ((ConstructorCallExpression) expression).getType();
+                } else if (expression instanceof MethodCallExpression) {
+                    int newOffset = ASTUtils.getOffset(doc, expression.getLineNumber(), expression.getColumnNumber());
+                    AstPath newPath = new AstPath(path.root(), newOffset, doc);
+                    guessedType = MethodInference.findCallerType(expression, newPath, doc, newOffset);
+                }
+            }
+        }
+    }
+
+
     @Override
-    public void visitVariableExpression(VariableExpression expression) {
-        if (expression == leaf) {
-            leafReached = true;
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        if (sameVariableName(leaf, expression.getLeftExpression())) {
+            Expression rightExpression = expression.getRightExpression();
+            if (rightExpression instanceof ConstantExpression
+                    && !rightExpression.getText().equals("null")) { // NOI18N
+                guessedType = ((ConstantExpression) rightExpression).getType();
+            } else if (rightExpression instanceof ConstructorCallExpression) {
+                guessedType = ((ConstructorCallExpression) rightExpression).getType();
+            } else if (rightExpression instanceof MethodCallExpression) {
+                guessedType = MethodInference.findCallerType(rightExpression, path, doc, cursorOffset);
+            } else if (rightExpression instanceof StaticMethodCallExpression) {
+                guessedType = MethodInference.findCallerType(rightExpression, path, doc, cursorOffset);
+            } else if (rightExpression instanceof ListExpression) {
+                guessedType = ((ListExpression) rightExpression).getType();
+            }
         }
+    }
+
+    @Override
+    public void visitVariableExpression(VariableExpression expression) {
+            if (expression.isSuperExpression()) {
+                guessedType = expression.getType().getSuperClass();
+            }
+            if (null != expression.getAccessedVariable()) {
+                Variable accessedVariable = expression.getAccessedVariable();
+
+                if (accessedVariable.hasInitialExpression()) {
+                    Expression initialExpression = expression.getAccessedVariable().getInitialExpression();
+                    if (initialExpression instanceof ConstantExpression
+                            && !initialExpression.getText().equals("null")) { // NOI18N
+                        guessedType = ((ConstantExpression) initialExpression).getType();
+                    } else if (initialExpression instanceof ConstructorCallExpression) {
+                        guessedType = ClassHelper.make(((ConstructorCallExpression) initialExpression).getType().getName());
+                    } else if (initialExpression instanceof MethodCallExpression) {
+                        int newOffset = ASTUtils.getOffset(doc, initialExpression.getLineNumber(), initialExpression.getColumnNumber());
+                        AstPath newPath = new AstPath(path.root(), newOffset, doc);
+                        guessedType = MethodInference.findCallerType(initialExpression, newPath, doc, newOffset);
+                    }
+                } else if (accessedVariable instanceof Parameter) {
+                    Parameter param = (Parameter) accessedVariable;
+                    guessedType = param.getType();
+                }
+            } else if (!expression.getType().getName().equals("java.lang.Object")) {
+                guessedType = expression.getType();
+
+            }
         super.visitVariableExpression(expression);
     }
 
@@ -99,7 +168,11 @@ public class TypeInferenceVisitor extends TypeVisitor {
                             && !rightExpression.getText().equals("null")) { // NOI18N
                         guessedType = ((ConstantExpression) rightExpression).getType();
                     } else if (rightExpression instanceof ConstructorCallExpression) {
-                        guessedType = ((ConstructorCallExpression) rightExpression).getType();
+                        guessedType = ClassHelper.make(((ConstructorCallExpression) rightExpression).getType().getName());
+                    } else if (rightExpression instanceof MethodCallExpression) {
+                        guessedType = MethodInference.findCallerType(rightExpression, path, doc, cursorOffset);
+                    } else if (rightExpression instanceof StaticMethodCallExpression) {
+                        guessedType = MethodInference.findCallerType(rightExpression, path, doc, cursorOffset);
                     }
                 }
             }
@@ -115,5 +188,10 @@ public class TypeInferenceVisitor extends TypeVisitor {
         return node1 instanceof VariableExpression && node2 instanceof VariableExpression
                 && ((VariableExpression) node1).getName().equals(((VariableExpression) node2).getName());
     }
+	
+    private static boolean sameVariableName(ASTNode node1, FieldNode node2) {
+        return node1 instanceof VariableExpression
+                && ((VariableExpression) node1).getName().equals(node2.getName());
+    }
 
 }
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/provider/MetaElementsProvider.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/provider/MetaElementsProvider.java
index f04648f..79994e2 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/provider/MetaElementsProvider.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/completion/provider/MetaElementsProvider.java
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import org.codehaus.groovy.reflection.CachedClass;
+import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.modules.groovy.editor.api.completion.CompletionItem.MetaMethodItem;
 import org.netbeans.modules.groovy.editor.api.completion.FieldSignature;
 import org.netbeans.modules.groovy.editor.api.completion.MethodSignature;
@@ -52,29 +53,47 @@ public final class MetaElementsProvider implements CompletionProvider {
     @Override
     public Map<MethodSignature, CompletionItem> getMethods(CompletionContext context) {
         final Map<MethodSignature, CompletionItem> result = new HashMap<MethodSignature, CompletionItem>();
-        final Class clz = loadClass(context.getTypeName());
+        final Class clz = loadClass(context);
         
         if (clz != null) {
             final MetaClass metaClz = GroovySystem.getMetaClassRegistry().getMetaClass(clz);
 
             if (metaClz != null) {
                 for (MetaMethod method : metaClz.getMetaMethods()) {
-                    populateProposal(clz, method, context.getPrefix(), context.getAnchor(), result, context.isNameOnly());
+                    if (!method.isStatic()) {
+                        populateProposal(clz, method, context.getPrefix(), context.getAnchor(), result, context.isNameOnly());
+                    }
                 }
             }
+            GroovySystem.getMetaClassRegistry().removeMetaClass(clz);
         }
         return result;
     }
 
     @Override
     public Map<MethodSignature, CompletionItem> getStaticMethods(CompletionContext context) {
-        return Collections.emptyMap();
+        final Map<MethodSignature, CompletionItem> result = new HashMap<MethodSignature, CompletionItem>();
+        final Class clz = loadClass(context);
+
+        if (clz != null) {
+            final MetaClass metaClz = GroovySystem.getMetaClassRegistry().getMetaClass(clz);
+
+            if (metaClz != null) {
+                for (MetaMethod method : metaClz.getMetaMethods()) {
+                    if (method.isStatic()) {
+                        populateProposal(clz, method, context.getPrefix(), context.getAnchor(), result, context.isNameOnly());
+                    }
+                }
+            }
+            GroovySystem.getMetaClassRegistry().removeMetaClass(clz);
+        }
+        return result;
     }
 
     @Override
     public Map<FieldSignature, CompletionItem> getFields(CompletionContext context) {
         final Map<FieldSignature, CompletionItem> result = new HashMap<FieldSignature, CompletionItem>();
-        final Class clazz = loadClass(context.getTypeName());
+        final Class clazz = loadClass(context);
         
         if (clazz != null) {
             final MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(clazz);
@@ -91,6 +110,7 @@ public final class MetaElementsProvider implements CompletionProvider {
                                 context.getAnchor()));
                     }
                 }
+                GroovySystem.getMetaClassRegistry().removeMetaClass(clazz);
             }
         }
         
@@ -102,6 +122,16 @@ public final class MetaElementsProvider implements CompletionProvider {
         return Collections.emptyMap();
     }
     
+    private Class loadClass(CompletionContext context) {
+        try {
+            return context.getSurroundingClass().getCompileUnit().getClassLoader().loadClass(context.getTypeName());
+        } catch (ClassNotFoundException cnfe) {
+            return loadClass(context.getTypeName());
+        } catch (RuntimeException exception) {
+            return null;
+        }
+    }
+
     private Class loadClass(String className) {
         try {
             // FIXME should be loaded by classpath classloader
@@ -226,6 +256,10 @@ public final class MetaElementsProvider implements CompletionProvider {
                 return false;
             }
         }
-        return false;
+        
+        //preferMethodsAccording to direct inheritance
+        
+        return currentMethod.getDeclaringClass().isAssignableFrom(methodToStore.getDeclaringClass().getTheClass());
+
     }
 }
diff --git a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/occurrences/TypeVisitor.java b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/occurrences/TypeVisitor.java
index 7c623d5..2952ccc 100644
--- a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/occurrences/TypeVisitor.java
+++ b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/occurrences/TypeVisitor.java
@@ -23,6 +23,7 @@ import java.util.Iterator;
 import org.codehaus.groovy.ast.*;
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.ClosureListExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.control.SourceUnit;
@@ -139,6 +140,9 @@ public class TypeVisitor extends ClassCodeVisitorSupport {
                         return;
                     }
                 }
+                else if (scope instanceof VariableExpression) {
+                    visitVariableExpression((VariableExpression)scope);
+                }
             }
         }
 
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy
new file mode 100644
index 0000000..190a831
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy
@@ -0,0 +1,33 @@
+class Klazz {
+
+    def fieldA = new String("Hello")
+    def fieldA1 = "Hello"
+    def fieldB = fieldA.c
+    def fieldB1 = fieldA1.c
+    def fieldC = fieldA.concat("b").c
+    def fieldC1 = fieldA1.concat("b").c
+    def fieldD =  "hi"
+    def fieldE = fieldA.concat(fieldD)
+    def fieldE1 = fieldA1.concat(fieldD)
+    def fieldF = fieldE.c
+    def fieldF1 = fieldE1.c
+    
+    def m() {
+    
+        def localA = "Hello"
+        localA.c
+    
+        localA.concat("b").c
+
+        def localB = "hi"
+
+        localA.concat(localB).c
+
+
+        def localC = localA.concat(localB)
+
+        localC.c
+
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_1.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_1.completion
new file mode 100644
index 0000000..4fde144
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_1.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+def fieldB = fieldA.c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_2.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_2.completion
new file mode 100644
index 0000000..53463bc
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_2.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+def fieldB1 = fieldA1.c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_3.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_3.completion
new file mode 100644
index 0000000..5fd3523
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_3.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+def fieldF = fieldE.c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_4.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_4.completion
new file mode 100644
index 0000000..493a7a6
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_4.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+localA.c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_5.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_5.completion
new file mode 100644
index 0000000..492308d
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_5.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+localA.concat("b").c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_6.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_6.completion
new file mode 100644
index 0000000..b471cd1
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_6.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+localA.concat(localB).c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_7.completion b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_7.completion
new file mode 100644
index 0000000..b210308
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/data/testfiles/completion/flow/completionReturnType1/CompletionReturnType1.groovy.testCompletionReturnType1_7.completion
@@ -0,0 +1,29 @@
+Code completion result for source line:
+localC.c|
+(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
+------------------------------------
+METHOD     capitalize()                               String
+METHOD     center(Number)                             String
+METHOD     center(Number, CharSequence)               String
+METHOD     charAt(int)                     [PUBLIC]   char
+METHOD     chars()                         [PUBLIC]   IntStream
+METHOD     codePointAt(int)                [PUBLIC]   int
+METHOD     codePointBefore(int)            [PUBLIC]   int
+METHOD     codePointCount(int, int)        [PUBLIC]   int
+METHOD     codePoints()                    [PUBLIC]   IntStream
+METHOD     collect()                                  Collection
+METHOD     collect(Closure)                           List
+METHOD     collect(Collection, Closure)               Collection
+METHOD     collectReplacements(Closure)               String
+METHOD     compareTo(String)               [PUBLIC]   int
+METHOD     compareTo(T)                    [PUBLIC]   int
+METHOD     compareToIgnoreCase(String)     [PUBLIC]   int
+METHOD     concat(String)                  [PUBLIC]   String
+METHOD     contains(CharSequence)          [PUBLIC]   boolean
+METHOD     contentEquals(CharSequence)     [PUBLIC]   boolean
+METHOD     contentEquals(StringBuffer)     [PUBLIC]   boolean
+METHOD     copyValueOf(char[])             [STATIC,   String
+METHOD     copyValueOf(char[], int, int)   [STATIC,   String
+METHOD     count(CharSequence)                        int
+FIELD      CASE_INSENSITIVE_ORDER          [STATIC,   Comparator<String>
+FIELD      class                           [PUBLIC]   Class
diff --git a/groovy/groovy.editor/test/unit/src/org/netbeans/modules/groovy/editor/api/completion/FlowCCTest.java b/groovy/groovy.editor/test/unit/src/org/netbeans/modules/groovy/editor/api/completion/FlowCCTest.java
new file mode 100644
index 0000000..dda6975
--- /dev/null
+++ b/groovy/groovy.editor/test/unit/src/org/netbeans/modules/groovy/editor/api/completion/FlowCCTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.netbeans.modules.groovy.editor.api.completion;
+
+/**
+ *
+ * @author sreimers
+ */
+public class FlowCCTest extends GroovyCCTestBase {
+
+    public FlowCCTest(String testName) {
+        super(testName);
+    }
+
+    @Override
+    protected String getTestType() {
+        return "flow"; //NOI18N
+    }
+
+    public void testCompletionReturnType1_1() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "def fieldB = fieldA.c^", false);
+    }
+
+    public void testCompletionReturnType1_2() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "def fieldB1 = fieldA1.c^", false);
+    }
+
+    public void testCompletionReturnType1_3() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "fieldE.c^", false);
+    }
+
+    public void testCompletionReturnType1_4() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "localA.c^", false);
+    }
+
+    public void testCompletionReturnType1_5() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "localA.concat(\"b\").c^", false);
+    }
+
+    public void testCompletionReturnType1_6() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "localA.concat(localB).c^", false);
+    }
+
+    public void testCompletionReturnType1_7() throws Exception {
+        checkCompletion(BASE + "CompletionReturnType1.groovy", "localC.c^", false);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists