This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 248884
Collapse All | Expand All

(-)a/php.editor/src/org/netbeans/modules/php/editor/completion/CompletionContextFinder.java (-49 / +40 lines)
Lines 68-73 Link Here
68
import org.netbeans.modules.php.editor.parser.astnodes.FunctionDeclaration;
68
import org.netbeans.modules.php.editor.parser.astnodes.FunctionDeclaration;
69
import org.netbeans.modules.php.editor.parser.astnodes.InterfaceDeclaration;
69
import org.netbeans.modules.php.editor.parser.astnodes.InterfaceDeclaration;
70
import org.netbeans.modules.php.editor.parser.astnodes.MethodDeclaration;
70
import org.netbeans.modules.php.editor.parser.astnodes.MethodDeclaration;
71
import org.netbeans.modules.php.editor.parser.astnodes.TraitDeclaration;
71
import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor;
72
import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor;
72
73
73
/**
74
/**
Lines 126-142 Link Here
126
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING},
127
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING},
127
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
128
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
128
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, COMBINED_USE_STATEMENT_TOKENS});
129
            new Object[]{PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_FUNCTION, COMBINED_USE_STATEMENT_TOKENS});
129
    private static final List<Object[]> USE_TRAIT_KEYWORD_TOKENS = Arrays.asList(
130
            new Object[]{TYPE_KEYWORD, PHPTokenId.WHITESPACE, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE},
131
            new Object[]{TYPE_KEYWORD, PHPTokenId.WHITESPACE, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE},
132
            new Object[]{TYPE_KEYWORD, PHPTokenId.WHITESPACE, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING},
133
            new Object[]{TYPE_KEYWORD, PHPTokenId.WHITESPACE, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
134
            new Object[]{TYPE_KEYWORD, PHPTokenId.WHITESPACE, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, COMBINED_USE_STATEMENT_TOKENS},
135
            new Object[]{TYPE_KEYWORD, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE},
136
            new Object[]{TYPE_KEYWORD, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE},
137
            new Object[]{TYPE_KEYWORD, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING},
138
            new Object[]{TYPE_KEYWORD, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
139
            new Object[]{TYPE_KEYWORD, PHPTokenId.PHP_CURLY_OPEN, PHPTokenId.WHITESPACE, PHPTokenId.PHP_USE, COMBINED_USE_STATEMENT_TOKENS});
140
    private static final List<Object[]> NAMESPACE_KEYWORD_TOKENS = Arrays.asList(
130
    private static final List<Object[]> NAMESPACE_KEYWORD_TOKENS = Arrays.asList(
141
            new Object[]{PHPTokenId.PHP_NAMESPACE},
131
            new Object[]{PHPTokenId.PHP_NAMESPACE},
142
            new Object[]{PHPTokenId.PHP_NAMESPACE, PHPTokenId.WHITESPACE},
132
            new Object[]{PHPTokenId.PHP_NAMESPACE, PHPTokenId.WHITESPACE},
Lines 293-300 Link Here
293
            return CompletionContext.PHPDOC;
283
            return CompletionContext.PHPDOC;
294
        } else if (acceptTokenChains(tokenSequence, CATCH_TOKENCHAINS, moveNextSucces)) {
284
        } else if (acceptTokenChains(tokenSequence, CATCH_TOKENCHAINS, moveNextSucces)) {
295
            return CompletionContext.CATCH;
285
            return CompletionContext.CATCH;
296
        } else if (acceptTokenChains(tokenSequence, USE_TRAIT_KEYWORD_TOKENS, moveNextSucces)) {
286
        } else if (acceptTokenChains(tokenSequence, NAMESPACE_KEYWORD_TOKENS, moveNextSucces)) {
297
            return CompletionContext.USE_TRAITS;
287
            return CompletionContext.NAMESPACE_KEYWORD;
288
        } else if (acceptTokenChains(tokenSequence, INSTANCEOF_TOKENCHAINS, moveNextSucces)) {
289
            return CompletionContext.TYPE_NAME;
290
        } else if (isInsideInterfaceDeclarationBlock(info, caretOffset, tokenSequence)) {
291
            CompletionContext paramContext = getParamaterContext(token, caretOffset, tokenSequence);
292
            if (paramContext != null) {
293
                return paramContext;
294
            }
295
            return CompletionContext.INTERFACE_CONTEXT_KEYWORDS;
296
        } else if (isInsideClassOrTraitDeclarationBlock(info, caretOffset, tokenSequence)) {
297
            if (acceptTokenChains(tokenSequence, USE_KEYWORD_TOKENS, moveNextSucces)) {
298
                return CompletionContext.USE_TRAITS;
299
            } else if (acceptTokenChains(tokenSequence, METHOD_NAME_TOKENCHAINS, moveNextSucces)) {
300
                return CompletionContext.METHOD_NAME;
301
            } else {
302
                CompletionContext paramContext = getParamaterContext(token, caretOffset, tokenSequence);
303
                if (paramContext != null) {
304
                    return paramContext;
305
                } else if (acceptTokenChains(tokenSequence, CLASS_CONTEXT_KEYWORDS_TOKENCHAINS, moveNextSucces)) {
306
                    return CompletionContext.CLASS_CONTEXT_KEYWORDS;
307
                }
308
                return CompletionContext.NONE;
309
            }
298
        } else if (acceptTokenChains(tokenSequence, GROUP_USE_KEYWORD_TOKENS, moveNextSucces)) {
310
        } else if (acceptTokenChains(tokenSequence, GROUP_USE_KEYWORD_TOKENS, moveNextSucces)) {
299
            return CompletionContext.GROUP_USE_KEYWORD;
311
            return CompletionContext.GROUP_USE_KEYWORD;
300
        } else if (acceptTokenChains(tokenSequence, GROUP_USE_CONST_KEYWORD_TOKENS, moveNextSucces)) {
312
        } else if (acceptTokenChains(tokenSequence, GROUP_USE_CONST_KEYWORD_TOKENS, moveNextSucces)) {
Lines 307-334 Link Here
307
            return CompletionContext.USE_CONST_KEYWORD;
319
            return CompletionContext.USE_CONST_KEYWORD;
308
        } else if (acceptTokenChains(tokenSequence, USE_FUNCTION_KEYWORD_TOKENS, moveNextSucces)) {
320
        } else if (acceptTokenChains(tokenSequence, USE_FUNCTION_KEYWORD_TOKENS, moveNextSucces)) {
309
            return CompletionContext.USE_FUNCTION_KEYWORD;
321
            return CompletionContext.USE_FUNCTION_KEYWORD;
310
        } else if (acceptTokenChains(tokenSequence, NAMESPACE_KEYWORD_TOKENS, moveNextSucces)) {
311
            return CompletionContext.NAMESPACE_KEYWORD;
312
        } else if (acceptTokenChains(tokenSequence, INSTANCEOF_TOKENCHAINS, moveNextSucces)) {
313
            return CompletionContext.TYPE_NAME;
314
        } else if (isInsideInterfaceDeclarationBlock(info, caretOffset, tokenSequence)) {
315
            CompletionContext paramContext = getParamaterContext(token, caretOffset, tokenSequence);
316
            if (paramContext != null) {
317
                return paramContext;
318
            }
319
            return CompletionContext.INTERFACE_CONTEXT_KEYWORDS;
320
        } else if (isInsideClassDeclarationBlock(info, caretOffset, tokenSequence)) {
321
            if (acceptTokenChains(tokenSequence, METHOD_NAME_TOKENCHAINS, moveNextSucces)) {
322
                return CompletionContext.METHOD_NAME;
323
            } else {
324
                CompletionContext paramContext = getParamaterContext(token, caretOffset, tokenSequence);
325
                if (paramContext != null) {
326
                    return paramContext;
327
                } else if (acceptTokenChains(tokenSequence, CLASS_CONTEXT_KEYWORDS_TOKENCHAINS, moveNextSucces)) {
328
                    return CompletionContext.CLASS_CONTEXT_KEYWORDS;
329
                }
330
                return CompletionContext.NONE;
331
            }
332
        } else if (acceptTokenChains(tokenSequence, FUNCTION_NAME_TOKENCHAINS, moveNextSucces)) {
322
        } else if (acceptTokenChains(tokenSequence, FUNCTION_NAME_TOKENCHAINS, moveNextSucces)) {
333
            return CompletionContext.NONE;
323
            return CompletionContext.NONE;
334
        } else if (isCommonCommentToken(tokenSequence)) {
324
        } else if (isCommonCommentToken(tokenSequence)) {
Lines 982-1015 Link Here
982
        return retval;
972
        return retval;
983
    }
973
    }
984
974
985
    private static synchronized boolean isInsideClassDeclarationBlock(ParserResult info,
975
    private static synchronized boolean isInsideClassOrTraitDeclarationBlock(ParserResult info,
986
            int caretOffset, TokenSequence tokenSequence) {
976
            int caretOffset, TokenSequence tokenSequence) {
987
        List<ASTNode> nodePath = NavUtils.underCaret(info, lexerToASTOffset(info, caretOffset));
977
        List<ASTNode> nodePath = NavUtils.underCaret(info, lexerToASTOffset(info, caretOffset));
988
        boolean methDecl = false;
978
        boolean methDecl = false;
989
        boolean funcDecl = false;
979
        boolean funcDecl = false;
990
        boolean clsDecl = false;
980
        boolean typeDecl = false;
991
        boolean isClassInsideFunc = false;
981
        boolean isTypeInsideFunc = false;
992
        boolean isFuncInsideClass = false;
982
        boolean isFuncInsideType = false;
993
        for (ASTNode aSTNode : nodePath) {
983
        for (ASTNode aSTNode : nodePath) {
994
            if (aSTNode instanceof FunctionDeclaration) {
984
            if (aSTNode instanceof FunctionDeclaration) {
995
                funcDecl = true;
985
                funcDecl = true;
996
                if (clsDecl) {
986
                if (typeDecl) {
997
                    isFuncInsideClass = true;
987
                    isFuncInsideType = true;
998
                }
988
                }
999
            } else if (aSTNode instanceof MethodDeclaration) {
989
            } else if (aSTNode instanceof MethodDeclaration) {
1000
                methDecl = true;
990
                methDecl = true;
1001
            } else if (aSTNode instanceof ClassDeclaration) {
991
            } else if (aSTNode instanceof ClassDeclaration
992
                    || aSTNode instanceof TraitDeclaration) {
1002
                if (aSTNode.getEndOffset() != caretOffset) {
993
                if (aSTNode.getEndOffset() != caretOffset) {
1003
                    clsDecl = true;
994
                    typeDecl = true;
1004
                    if (funcDecl) {
995
                    if (funcDecl) {
1005
                        isClassInsideFunc = true;
996
                        isTypeInsideFunc = true;
1006
                    }
997
                    }
1007
                } else {
998
                } else {
1008
                    return false;
999
                    return false;
1009
                }
1000
                }
1010
            }
1001
            }
1011
        }
1002
        }
1012
        if (funcDecl && !methDecl && !clsDecl) {
1003
        if (funcDecl && !methDecl && !typeDecl) {
1013
            final StringBuilder sb = new StringBuilder();
1004
            final StringBuilder sb = new StringBuilder();
1014
            new DefaultVisitor() {
1005
            new DefaultVisitor() {
1015
1006
Lines 1023-1029 Link Here
1023
                return false;
1014
                return false;
1024
            }
1015
            }
1025
        }
1016
        }
1026
        if (isClassInsideFunc && !isFuncInsideClass) {
1017
        if (isTypeInsideFunc && !isFuncInsideType) {
1027
            return true;
1018
            return true;
1028
        }
1019
        }
1029
        int orgOffset = tokenSequence.offset();
1020
        int orgOffset = tokenSequence.offset();
Lines 1046-1054 Link Here
1046
                        || id.equals(PHPTokenId.PHP_CATCH))
1037
                        || id.equals(PHPTokenId.PHP_CATCH))
1047
                        && (curlyOpen > curlyClose)) {
1038
                        && (curlyOpen > curlyClose)) {
1048
                    return false;
1039
                    return false;
1049
                } else if (id.equals(PHPTokenId.PHP_CLASS)) {
1040
                } else if (id.equals(PHPTokenId.PHP_CLASS) || id.equals(PHPTokenId.PHP_TRAIT)) {
1050
                    boolean isClassScope = curlyOpen > 0 && (curlyOpen > curlyClose);
1041
                    boolean isTypeScope = curlyOpen > 0 && (curlyOpen > curlyClose);
1051
                    return isClassScope;
1042
                    return isTypeScope;
1052
                }
1043
                }
1053
            }
1044
            }
1054
        } finally {
1045
        } finally {
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php (+35 lines)
Line 0 Link Here
1
<?php
2
3
trait FirstTrait {
4
}
5
6
trait SecondTrait {
7
}
8
9
trait T {
10
11
    use FirstTrait; // test trait first
12
    use SecondTrait; // test trait second
13
14
}
15
16
trait U {
17
18
    public static $sf = "static field";
19
    use FirstTrait; // test after field
20
21
}
22
23
class A {
24
25
    use FirstTrait; // test class first
26
    use SecondTrait; // test class second
27
28
}
29
30
class B {
31
32
    const CONSTANT = "CONSTANT";
33
    use FirstTrait; // test after const
34
35
}
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testAfterConst.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |FirstTrait; // test after const
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testAfterField.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |FirstTrait; // test after field
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testFirstTraitInClass.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |FirstTrait; // test class first
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testFirstTraitInTrait.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |FirstTrait; // test trait first
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testSecondTraitInClass.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |SecondTrait; // test class second
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/data/testfiles/completion/lib/tests248884/issue248884.php.testSecondTraitInTrait.completion (+7 lines)
Line 0 Link Here
1
Code completion result for source line:
2
use |SecondTrait; // test trait second
3
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
4
CLASS      FirstTrait                      [PUBLIC]   issue248884.php
5
CLASS      SecondTrait                     [PUBLIC]   issue248884.php
6
CLASS      T                               [PUBLIC]   issue248884.php
7
CLASS      U                               [PUBLIC]   issue248884.php
(-)a/php.editor/test/unit/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletion248884Test.java (+93 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2016 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.php.editor.completion;
43
44
import java.io.File;
45
import java.util.Collections;
46
import java.util.Map;
47
import org.netbeans.api.java.classpath.ClassPath;
48
import org.netbeans.modules.php.project.api.PhpSourcePath;
49
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
50
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileUtil;
52
53
public class PHPCodeCompletion248884Test extends PHPCodeCompletionTestBase {
54
55
    public PHPCodeCompletion248884Test(String testName) {
56
        super(testName);
57
    }
58
59
    @Override
60
    protected Map<String, ClassPath> createClassPathsForTest() {
61
        return Collections.singletonMap(
62
            PhpSourcePath.SOURCE_CP,
63
            ClassPathSupport.createClassPath(new FileObject[]{
64
                FileUtil.toFileObject(new File(getDataDir(), "/testfiles/completion/lib/tests248884/"))
65
            })
66
        );
67
    }
68
69
    public void testFirstTraitInTrait() throws Exception {
70
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^FirstTrait; // test trait first", false);
71
    }
72
73
    public void testSecondTraitInTrait() throws Exception {
74
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^SecondTrait; // test trait second", false);
75
    }
76
77
    public void testFirstTraitInClass() throws Exception {
78
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^FirstTrait; // test class first", false);
79
    }
80
81
    public void testSecondTraitInClass() throws Exception {
82
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^SecondTrait; // test class second", false);
83
    }
84
85
    public void testAfterConst() throws Exception {
86
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^FirstTrait; // test after const", false);
87
    }
88
89
    public void testAfterField() throws Exception {
90
        checkCompletion("testfiles/completion/lib/tests248884/issue248884.php", "use ^FirstTrait; // test after field", false);
91
    }
92
93
}

Return to bug 248884