mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
@@ -24,4 +24,5 @@ public interface RegExpLanguageHost {
|
||||
boolean supportsPossessiveQuantifiers();
|
||||
boolean supportsPythonNamedGroups();
|
||||
boolean supportsPythonConditionalRefs();
|
||||
boolean supportsRubyNamedGroups();
|
||||
}
|
||||
|
||||
@@ -23,417 +23,462 @@ import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings({ "RedundantIfStatement" })
|
||||
@SuppressWarnings({"RedundantIfStatement"})
|
||||
public class RegExpParser implements PsiParser {
|
||||
private boolean myAllowDanglingMetacharacters;
|
||||
private boolean myAllowOmitNumbersInQuantifiers;
|
||||
|
||||
public void setAllowDanglingMetacharacters(boolean allowDanglingMetacharacters) {
|
||||
myAllowDanglingMetacharacters = allowDanglingMetacharacters;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ASTNode parse(IElementType root, PsiBuilder builder) {
|
||||
public void setAllowOmitNumbersInQuantifiers(boolean allowOmitNumbersInQuantifiers) {
|
||||
myAllowOmitNumbersInQuantifiers = allowOmitNumbersInQuantifiers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ASTNode parse(IElementType root, PsiBuilder builder) {
|
||||
// builder.setDebugMode(true);
|
||||
final PsiBuilder.Marker rootMarker = builder.mark();
|
||||
final PsiBuilder.Marker rootMarker = builder.mark();
|
||||
|
||||
parsePattern(builder);
|
||||
parsePattern(builder);
|
||||
|
||||
while (!builder.eof()) {
|
||||
patternExpected(builder);
|
||||
builder.advanceLexer();
|
||||
}
|
||||
|
||||
rootMarker.done(root);
|
||||
return builder.getTreeBuilt();
|
||||
while (!builder.eof()) {
|
||||
patternExpected(builder);
|
||||
builder.advanceLexer();
|
||||
}
|
||||
|
||||
rootMarker.done(root);
|
||||
return builder.getTreeBuilt();
|
||||
}
|
||||
|
||||
/**
|
||||
* PATTERN ::= BRANCH "|" PATTERN | BRANCH
|
||||
*/
|
||||
private boolean parsePattern(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (!parseBranch(builder)) {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* PATTERN ::= BRANCH "|" PATTERN | BRANCH
|
||||
*/
|
||||
private boolean parsePattern(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
while (builder.getTokenType() == RegExpTT.UNION) {
|
||||
builder.advanceLexer();
|
||||
if (!parseBranch(builder)) {
|
||||
// TODO: no test coverage
|
||||
patternExpected(builder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
marker.done(RegExpElementTypes.PATTERN);
|
||||
|
||||
return true;
|
||||
if (!parseBranch(builder)) {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* BRANCH ::= ATOM BRANCH | ""
|
||||
*/
|
||||
@SuppressWarnings({ "StatementWithEmptyBody" })
|
||||
private boolean parseBranch(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
while (builder.getTokenType() == RegExpTT.UNION) {
|
||||
builder.advanceLexer();
|
||||
if (!parseBranch(builder)) {
|
||||
// TODO: no test coverage
|
||||
patternExpected(builder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parseAtom(builder)) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.GROUP_END || token == RegExpTT.UNION || token == null) {
|
||||
// empty branches are allowed
|
||||
marker.done(RegExpElementTypes.BRANCH);
|
||||
return true;
|
||||
}
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
marker.done(RegExpElementTypes.PATTERN);
|
||||
|
||||
for (;parseAtom(builder);) ;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* BRANCH ::= ATOM BRANCH | ""
|
||||
*/
|
||||
@SuppressWarnings({"StatementWithEmptyBody"})
|
||||
private boolean parseBranch(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (!parseAtom(builder)) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.GROUP_END || token == RegExpTT.UNION || token == null) {
|
||||
// empty branches are allowed
|
||||
marker.done(RegExpElementTypes.BRANCH);
|
||||
return true;
|
||||
}
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ATOM ::= CLOSURE | GROUP
|
||||
* CLOSURE ::= GROUP QUANTIFIER
|
||||
*/
|
||||
private boolean parseAtom(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = parseGroup(builder);
|
||||
for (; parseAtom(builder);) ;
|
||||
|
||||
if (marker == null) {
|
||||
return false;
|
||||
}
|
||||
marker = marker.precede();
|
||||
marker.done(RegExpElementTypes.BRANCH);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parseQuantifier(builder)) {
|
||||
marker.done(RegExpElementTypes.CLOSURE);
|
||||
} else {
|
||||
marker.drop();
|
||||
}
|
||||
/**
|
||||
* ATOM ::= CLOSURE | GROUP
|
||||
* CLOSURE ::= GROUP QUANTIFIER
|
||||
*/
|
||||
private boolean parseAtom(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = parseGroup(builder);
|
||||
|
||||
return true;
|
||||
if (marker == null) {
|
||||
return false;
|
||||
}
|
||||
marker = marker.precede();
|
||||
|
||||
if (parseQuantifier(builder)) {
|
||||
marker.done(RegExpElementTypes.CLOSURE);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
}
|
||||
|
||||
/**
|
||||
* QUANTIFIER ::= Q TYPE | ""
|
||||
* Q ::= "{" BOUND "}" | "*" | "?" | "+"
|
||||
* BOUND ::= NUM | NUM "," | NUM "," NUM
|
||||
* TYPE ::= "?" | "+" | ""
|
||||
*/
|
||||
private boolean parseQuantifier(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (builder.getTokenType() == RegExpTT.LBRACE) {
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() != RegExpTT.NUMBER && myAllowDanglingMetacharacters) {
|
||||
marker.done(RegExpTT.CHARACTER);
|
||||
return true;
|
||||
}
|
||||
checkMatches(builder, RegExpTT.NUMBER, "Number expected");
|
||||
if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.advanceLexer();
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
} else {
|
||||
checkMatches(builder, RegExpTT.COMMA, "',' expected");
|
||||
if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.advanceLexer();
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
} else if (builder.getTokenType() == RegExpTT.NUMBER) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.RBRACE, "'}' expected");
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
} else {
|
||||
builder.error("'}' or number expected");
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (RegExpTT.QUANTIFIERS.contains(builder.getTokenType())) {
|
||||
builder.advanceLexer();
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
} else {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* QUANTIFIER ::= Q TYPE | ""
|
||||
* Q ::= "{" BOUND "}" | "*" | "?" | "+"
|
||||
* BOUND ::= NUM | NUM "," | NUM "," NUM
|
||||
* TYPE ::= "?" | "+" | ""
|
||||
*/
|
||||
private boolean parseQuantifier(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void parseQuantifierType(PsiBuilder builder) {
|
||||
if (builder.getTokenType() == RegExpTT.PLUS) {
|
||||
builder.advanceLexer();
|
||||
} else if (builder.getTokenType() == RegExpTT.QUEST) {
|
||||
builder.advanceLexer();
|
||||
} else {
|
||||
if (RegExpTT.QUANTIFIERS.contains(builder.getTokenType())) {
|
||||
builder.error("Dangling metacharacter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CLASS ::= "[" NEGATION DEFLIST "]"
|
||||
* NEGATION ::= "^" | ""
|
||||
* DEFLIST ::= INTERSECTION DEFLIST
|
||||
* INTERSECTION ::= INTERSECTION "&&" CLASSDEF | CLASSDEF
|
||||
* CLASSDEF ::= CLASS | SIMPLE_CLASSDEF | ""
|
||||
* SIMPLE_CLASSDEF ::= CHARACTER | CHARACTER "-" CLASSDEF
|
||||
*/
|
||||
private PsiBuilder.Marker parseClass(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
if (builder.getTokenType() == RegExpTT.LBRACE) {
|
||||
builder.advanceLexer();
|
||||
boolean minOmitted = false;
|
||||
if (builder.getTokenType() == RegExpTT.COMMA && myAllowOmitNumbersInQuantifiers) {
|
||||
minOmitted = true;
|
||||
builder.advanceLexer();
|
||||
|
||||
if (builder.getTokenType() == RegExpTT.CARET) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
|
||||
// DEFLIST
|
||||
if (parseClassIntersection(builder)) {
|
||||
while (RegExpTT.CHARACTERS2.contains(builder.getTokenType())
|
||||
|| builder.getTokenType() == RegExpTT.CLASS_BEGIN
|
||||
|| builder.getTokenType() == RegExpTT.PROPERTY)
|
||||
{
|
||||
parseClassIntersection(builder);
|
||||
}
|
||||
}
|
||||
|
||||
checkMatches(builder, RegExpTT.CLASS_END, "Unclosed character class");
|
||||
marker.done(RegExpElementTypes.CLASS);
|
||||
return marker;
|
||||
}
|
||||
|
||||
private boolean parseClassIntersection(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (!parseClassdef(builder, false)) {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
while (RegExpTT.ANDAND == builder.getTokenType()) {
|
||||
builder.advanceLexer();
|
||||
parseClassdef(builder, true);
|
||||
marker.done(RegExpElementTypes.INTERSECTION);
|
||||
marker = marker.precede();
|
||||
}
|
||||
|
||||
marker.drop();
|
||||
}
|
||||
else if (builder.getTokenType() != RegExpTT.NUMBER && myAllowDanglingMetacharacters) {
|
||||
marker.done(RegExpTT.CHARACTER);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean parseClassdef(PsiBuilder builder, boolean mayBeEmpty) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.CLASS_BEGIN) {
|
||||
parseClass(builder);
|
||||
} else if (RegExpTT.CHARACTERS2.contains(token)) {
|
||||
parseSimpleClassdef(builder);
|
||||
} else if (token == RegExpTT.PROPERTY) {
|
||||
parseProperty(builder);
|
||||
} else if (mayBeEmpty) {
|
||||
// TODO: no test coverage
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseSimpleClassdef(PsiBuilder builder) {
|
||||
assert RegExpTT.CHARACTERS2.contains(builder.getTokenType());
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
makeChar(builder);
|
||||
|
||||
IElementType t = builder.getTokenType();
|
||||
if (t == RegExpTT.MINUS) {
|
||||
final PsiBuilder.Marker m = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
t = builder.getTokenType();
|
||||
if (RegExpTT.CHARACTERS2.contains(t)) {
|
||||
m.drop();
|
||||
makeChar(builder);
|
||||
marker.done(RegExpElementTypes.CHAR_RANGE);
|
||||
} else {
|
||||
marker.drop();
|
||||
m.done(t == RegExpTT.CHAR_CLASS ?
|
||||
RegExpElementTypes.SIMPLE_CLASS :
|
||||
RegExpElementTypes.CHAR);
|
||||
|
||||
if (t == RegExpTT.CLASS_END) { // [a-]
|
||||
return;
|
||||
} else if (t == RegExpTT.CLASS_BEGIN) { // [a-[b]]
|
||||
if (parseClassdef(builder, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
builder.error("Illegal character range");
|
||||
}
|
||||
} else {
|
||||
marker.drop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeChar(PsiBuilder builder) {
|
||||
final IElementType t = builder.getTokenType();
|
||||
PsiBuilder.Marker m = builder.mark();
|
||||
}
|
||||
else {
|
||||
checkMatches(builder, RegExpTT.NUMBER, "Number expected");
|
||||
}
|
||||
if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.advanceLexer();
|
||||
m.done(t == RegExpTT.CHAR_CLASS ?
|
||||
RegExpElementTypes.SIMPLE_CLASS :
|
||||
RegExpElementTypes.CHAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* GROUP ::= "(" PATTERN ")" | TERM
|
||||
* TERM ::= "." | "$" | "^" | CHAR | CLASS | BACKREF
|
||||
*/
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseGroup(PsiBuilder builder) {
|
||||
final IElementType type = builder.getTokenType();
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (RegExpTT.GROUPS.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
if (!parsePattern(builder)) {
|
||||
patternExpected(builder);
|
||||
} else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
} else if (type == RegExpTT.SET_OPTIONS) {
|
||||
builder.advanceLexer();
|
||||
|
||||
final PsiBuilder.Marker o = builder.mark();
|
||||
if (builder.getTokenType() == RegExpTT.OPTIONS_ON) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
if (builder.getTokenType() == RegExpTT.OPTIONS_OFF) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
o.done(RegExpElementTypes.OPTIONS);
|
||||
|
||||
if (builder.getTokenType() == RegExpTT.COLON) {
|
||||
builder.advanceLexer();
|
||||
if (!parsePattern(builder)) {
|
||||
// TODO: no test coverage
|
||||
patternExpected(builder);
|
||||
} else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
} else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed options group");
|
||||
marker.done(RegExpElementTypes.SET_OPTIONS);
|
||||
}
|
||||
} else if (type == StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN) {
|
||||
builder.error("Illegal/unsupported escape sequence");
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
} else if (RegExpTT.CHARACTERS.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
} else if (RegExpTT.BOUNDARIES.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.BOUNDARY);
|
||||
} else if (type == RegExpTT.BACKREF) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.BACKREF);
|
||||
} else if (type == RegExpTT.PYTHON_NAMED_GROUP) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.NAME, "Group name expected");
|
||||
checkMatches(builder, RegExpTT.GT, "Unclosed group name");
|
||||
if (!parsePattern(builder)) {
|
||||
patternExpected(builder);
|
||||
} else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
} else if (type == RegExpTT.PYTHON_NAMED_GROUP_REF) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.NAME, "Group name expected");
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group reference");
|
||||
marker.done(RegExpElementTypes.PY_NAMED_GROUP_REF);
|
||||
} else if (type == RegExpTT.PYTHON_COND_REF) {
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() == RegExpTT.NAME || builder.getTokenType() == RegExpTT.NUMBER) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
builder.error("Group name or number expected");
|
||||
}
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group reference");
|
||||
if (!parseBranch(builder)) {
|
||||
patternExpected(builder);
|
||||
} else {
|
||||
if (builder.getTokenType() == RegExpTT.UNION) {
|
||||
builder.advanceLexer();
|
||||
if (!parseBranch(builder)) {
|
||||
patternExpected(builder);
|
||||
}
|
||||
}
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.PY_COND_REF);
|
||||
} else if (type == RegExpTT.PROPERTY) {
|
||||
parseProperty(builder);
|
||||
marker.done(RegExpElementTypes.PROPERTY);
|
||||
} else if (RegExpTT.SIMPLE_CLASSES.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.SIMPLE_CLASS);
|
||||
} else if (type == RegExpTT.CLASS_BEGIN) {
|
||||
marker.drop();
|
||||
return parseClass(builder);
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
}
|
||||
else {
|
||||
if (!minOmitted) {
|
||||
checkMatches(builder, RegExpTT.COMMA, "',' expected");
|
||||
}
|
||||
else if (type == RegExpTT.LBRACE && myAllowDanglingMetacharacters) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.advanceLexer();
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
}
|
||||
else if (builder.getTokenType() == RegExpTT.NUMBER) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.RBRACE, "'}' expected");
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
return null;
|
||||
builder.error("'}' or number expected");
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
return true;
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
else if (RegExpTT.QUANTIFIERS.contains(builder.getTokenType())) {
|
||||
builder.advanceLexer();
|
||||
parseQuantifierType(builder);
|
||||
marker.done(RegExpElementTypes.QUANTIFIER);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void parseProperty(PsiBuilder builder) {
|
||||
checkMatches(builder, RegExpTT.PROPERTY, "'\\p' expected");
|
||||
return true;
|
||||
}
|
||||
|
||||
checkMatches(builder, RegExpTT.LBRACE, "Character category expected");
|
||||
if (builder.getTokenType() == RegExpTT.NAME) {
|
||||
builder.advanceLexer();
|
||||
} else if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.error("Empty character family");
|
||||
} else {
|
||||
builder.error("Character family name expected");
|
||||
builder.advanceLexer();
|
||||
}
|
||||
checkMatches(builder, RegExpTT.RBRACE, "Unclosed character family");
|
||||
private static void parseQuantifierType(PsiBuilder builder) {
|
||||
if (builder.getTokenType() == RegExpTT.PLUS) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else if (builder.getTokenType() == RegExpTT.QUEST) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
if (RegExpTT.QUANTIFIERS.contains(builder.getTokenType())) {
|
||||
builder.error("Dangling metacharacter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CLASS ::= "[" NEGATION DEFLIST "]"
|
||||
* NEGATION ::= "^" | ""
|
||||
* DEFLIST ::= INTERSECTION DEFLIST
|
||||
* INTERSECTION ::= INTERSECTION "&&" CLASSDEF | CLASSDEF
|
||||
* CLASSDEF ::= CLASS | SIMPLE_CLASSDEF | ""
|
||||
* SIMPLE_CLASSDEF ::= CHARACTER | CHARACTER "-" CLASSDEF
|
||||
*/
|
||||
private PsiBuilder.Marker parseClass(PsiBuilder builder) {
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
if (builder.getTokenType() == RegExpTT.CARET) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
|
||||
private static void patternExpected(PsiBuilder builder) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.GROUP_END) {
|
||||
builder.error("Unmatched closing ')'");
|
||||
} else if (RegExpTT.QUANTIFIERS.contains(token)) {
|
||||
builder.error("Dangling metacharacter");
|
||||
} else {
|
||||
builder.error("Pattern expected");
|
||||
}
|
||||
// DEFLIST
|
||||
if (parseClassIntersection(builder)) {
|
||||
while (RegExpTT.CHARACTERS2.contains(builder.getTokenType()) ||
|
||||
builder.getTokenType() == RegExpTT.CLASS_BEGIN ||
|
||||
builder.getTokenType() == RegExpTT.PROPERTY) {
|
||||
parseClassIntersection(builder);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void checkMatches(final PsiBuilder builder, final IElementType token, final String message) {
|
||||
if (builder.getTokenType() == token) {
|
||||
builder.advanceLexer();
|
||||
} else {
|
||||
builder.error(message);
|
||||
}
|
||||
checkMatches(builder, RegExpTT.CLASS_END, "Unclosed character class");
|
||||
marker.done(RegExpElementTypes.CLASS);
|
||||
return marker;
|
||||
}
|
||||
|
||||
private boolean parseClassIntersection(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (!parseClassdef(builder, false)) {
|
||||
marker.drop();
|
||||
return false;
|
||||
}
|
||||
while (RegExpTT.ANDAND == builder.getTokenType()) {
|
||||
builder.advanceLexer();
|
||||
parseClassdef(builder, true);
|
||||
marker.done(RegExpElementTypes.INTERSECTION);
|
||||
marker = marker.precede();
|
||||
}
|
||||
|
||||
marker.drop();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean parseClassdef(PsiBuilder builder, boolean mayBeEmpty) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.CLASS_BEGIN) {
|
||||
parseClass(builder);
|
||||
}
|
||||
else if (RegExpTT.CHARACTERS2.contains(token)) {
|
||||
parseSimpleClassdef(builder);
|
||||
}
|
||||
else if (token == RegExpTT.PROPERTY) {
|
||||
parseProperty(builder);
|
||||
}
|
||||
else if (mayBeEmpty) {
|
||||
// TODO: no test coverage
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void parseSimpleClassdef(PsiBuilder builder) {
|
||||
assert RegExpTT.CHARACTERS2.contains(builder.getTokenType());
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
makeChar(builder);
|
||||
|
||||
IElementType t = builder.getTokenType();
|
||||
if (t == RegExpTT.MINUS) {
|
||||
final PsiBuilder.Marker m = builder.mark();
|
||||
builder.advanceLexer();
|
||||
|
||||
t = builder.getTokenType();
|
||||
if (RegExpTT.CHARACTERS2.contains(t)) {
|
||||
m.drop();
|
||||
makeChar(builder);
|
||||
marker.done(RegExpElementTypes.CHAR_RANGE);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
m.done(t == RegExpTT.CHAR_CLASS ? RegExpElementTypes.SIMPLE_CLASS : RegExpElementTypes.CHAR);
|
||||
|
||||
if (t == RegExpTT.CLASS_END) { // [a-]
|
||||
return;
|
||||
}
|
||||
else if (t == RegExpTT.CLASS_BEGIN) { // [a-[b]]
|
||||
if (parseClassdef(builder, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
builder.error("Illegal character range");
|
||||
}
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeChar(PsiBuilder builder) {
|
||||
final IElementType t = builder.getTokenType();
|
||||
PsiBuilder.Marker m = builder.mark();
|
||||
builder.advanceLexer();
|
||||
m.done(t == RegExpTT.CHAR_CLASS ? RegExpElementTypes.SIMPLE_CLASS : RegExpElementTypes.CHAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* GROUP ::= "(" PATTERN ")" | TERM
|
||||
* TERM ::= "." | "$" | "^" | CHAR | CLASS | BACKREF
|
||||
*/
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseGroup(PsiBuilder builder) {
|
||||
final IElementType type = builder.getTokenType();
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
|
||||
if (RegExpTT.GROUPS.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
if (!parsePattern(builder)) {
|
||||
patternExpected(builder);
|
||||
}
|
||||
else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
}
|
||||
else if (type == RegExpTT.SET_OPTIONS) {
|
||||
builder.advanceLexer();
|
||||
|
||||
final PsiBuilder.Marker o = builder.mark();
|
||||
if (builder.getTokenType() == RegExpTT.OPTIONS_ON) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
if (builder.getTokenType() == RegExpTT.OPTIONS_OFF) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
o.done(RegExpElementTypes.OPTIONS);
|
||||
|
||||
if (builder.getTokenType() == RegExpTT.COLON) {
|
||||
builder.advanceLexer();
|
||||
if (!parsePattern(builder)) {
|
||||
// TODO: no test coverage
|
||||
patternExpected(builder);
|
||||
}
|
||||
else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
}
|
||||
else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed options group");
|
||||
marker.done(RegExpElementTypes.SET_OPTIONS);
|
||||
}
|
||||
}
|
||||
else if (type == StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN) {
|
||||
builder.error("Illegal/unsupported escape sequence");
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
}
|
||||
else if (RegExpTT.CHARACTERS.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
}
|
||||
else if (RegExpTT.BOUNDARIES.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.BOUNDARY);
|
||||
}
|
||||
else if (type == RegExpTT.BACKREF) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.BACKREF);
|
||||
}
|
||||
else if (type == RegExpTT.PYTHON_NAMED_GROUP || type == RegExpTT.RUBY_NAMED_GROUP || type == RegExpTT.RUBY_QUOTED_NAMED_GROUP) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.NAME, "Group name expected");
|
||||
checkMatches(builder, type == RegExpTT.RUBY_QUOTED_NAMED_GROUP ? RegExpTT.QUOTE : RegExpTT.GT, "Unclosed group name");
|
||||
if (!parsePattern(builder)) {
|
||||
patternExpected(builder);
|
||||
}
|
||||
else {
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.GROUP);
|
||||
}
|
||||
else if (type == RegExpTT.PYTHON_NAMED_GROUP_REF) {
|
||||
builder.advanceLexer();
|
||||
checkMatches(builder, RegExpTT.NAME, "Group name expected");
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group reference");
|
||||
marker.done(RegExpElementTypes.PY_NAMED_GROUP_REF);
|
||||
}
|
||||
else if (type == RegExpTT.PYTHON_COND_REF) {
|
||||
builder.advanceLexer();
|
||||
if (builder.getTokenType() == RegExpTT.NAME || builder.getTokenType() == RegExpTT.NUMBER) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
builder.error("Group name or number expected");
|
||||
}
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group reference");
|
||||
if (!parseBranch(builder)) {
|
||||
patternExpected(builder);
|
||||
}
|
||||
else {
|
||||
if (builder.getTokenType() == RegExpTT.UNION) {
|
||||
builder.advanceLexer();
|
||||
if (!parseBranch(builder)) {
|
||||
patternExpected(builder);
|
||||
}
|
||||
}
|
||||
checkMatches(builder, RegExpTT.GROUP_END, "Unclosed group");
|
||||
}
|
||||
marker.done(RegExpElementTypes.PY_COND_REF);
|
||||
}
|
||||
else if (type == RegExpTT.PROPERTY) {
|
||||
parseProperty(builder);
|
||||
marker.done(RegExpElementTypes.PROPERTY);
|
||||
}
|
||||
else if (RegExpTT.SIMPLE_CLASSES.contains(type)) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.SIMPLE_CLASS);
|
||||
}
|
||||
else if (type == RegExpTT.CLASS_BEGIN) {
|
||||
marker.drop();
|
||||
return parseClass(builder);
|
||||
}
|
||||
else if (type == RegExpTT.LBRACE && myAllowDanglingMetacharacters) {
|
||||
builder.advanceLexer();
|
||||
marker.done(RegExpElementTypes.CHAR);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
return null;
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
private static void parseProperty(PsiBuilder builder) {
|
||||
checkMatches(builder, RegExpTT.PROPERTY, "'\\p' expected");
|
||||
|
||||
checkMatches(builder, RegExpTT.LBRACE, "Character category expected");
|
||||
if (builder.getTokenType() == RegExpTT.NAME) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else if (builder.getTokenType() == RegExpTT.RBRACE) {
|
||||
builder.error("Empty character family");
|
||||
}
|
||||
else {
|
||||
builder.error("Character family name expected");
|
||||
builder.advanceLexer();
|
||||
}
|
||||
checkMatches(builder, RegExpTT.RBRACE, "Unclosed character family");
|
||||
}
|
||||
|
||||
private static void patternExpected(PsiBuilder builder) {
|
||||
final IElementType token = builder.getTokenType();
|
||||
if (token == RegExpTT.GROUP_END) {
|
||||
builder.error("Unmatched closing ')'");
|
||||
}
|
||||
else if (RegExpTT.QUANTIFIERS.contains(token)) {
|
||||
builder.error("Dangling metacharacter");
|
||||
}
|
||||
else {
|
||||
builder.error("Pattern expected");
|
||||
}
|
||||
}
|
||||
|
||||
protected static void checkMatches(final PsiBuilder builder, final IElementType token, final String message) {
|
||||
if (builder.getTokenType() == token) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
else {
|
||||
builder.error(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,10 @@ public interface RegExpTT {
|
||||
IElementType DOT = new RegExpElementType("DOT");
|
||||
IElementType UNION = new RegExpElementType("UNION");
|
||||
|
||||
// > in Python named group
|
||||
// > in Python/Ruby named group
|
||||
IElementType GT = new RegExpElementType("GT");
|
||||
// ' in Ruby quoted named group
|
||||
IElementType QUOTE = new RegExpElementType("QUOTE");
|
||||
|
||||
// "\b" | "\t" | "\f" | "\r" | "\n"
|
||||
IElementType CTRL_CHARACTER = new RegExpElementType("CTRL_CHARACTER");
|
||||
@@ -107,6 +109,11 @@ public interface RegExpTT {
|
||||
// (?(id/name)yes-pattern|no-pattern)
|
||||
IElementType PYTHON_COND_REF = new RegExpElementType("PYTHON_COND_REF");
|
||||
|
||||
// (?<name>...
|
||||
IElementType RUBY_NAMED_GROUP = new RegExpElementType("RUBY_NAMED_GROUP");
|
||||
|
||||
// (?'name'...
|
||||
IElementType RUBY_QUOTED_NAMED_GROUP = new RegExpElementType("RUBY_QUOTED_NAMED_GROUP");
|
||||
|
||||
TokenSet KEYWORDS = TokenSet.create(DOT, STAR, QUEST, PLUS);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/* The following code was generated by JFlex 1.4.3 on 22.03.10 22:06 */
|
||||
/* The following code was generated by JFlex 1.4.3 on 01.06.10 15:51 */
|
||||
|
||||
/* It's an automatically generated code. Do not modify it. */
|
||||
package org.intellij.lang.regexp;
|
||||
|
||||
import com.intellij.lexer.FlexLexer;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import java.util.LinkedList;
|
||||
import com.intellij.psi.StringEscapesTokenTypes;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
// IDEADEV-11055
|
||||
@SuppressWarnings({ "ALL", "SameParameterValue", "WeakerAccess", "SameReturnValue", "RedundantThrows", "UnusedDeclaration", "UnusedDeclaration" })
|
||||
@@ -14,8 +15,8 @@ import com.intellij.psi.StringEscapesTokenTypes;
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
|
||||
* on 22.03.10 22:06 from the specification file
|
||||
* <tt>C:/JetBrains/IDEA/tools/lexer/../../community/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex</tt>
|
||||
* on 01.06.10 15:51 from the specification file
|
||||
* <tt>C:/JetBrains/idea.branches/maia/tools/lexer/../../community/RegExpSupport/src/org/intellij/lang/regexp/regexp-lexer.flex</tt>
|
||||
*/
|
||||
class _RegExLexer implements FlexLexer {
|
||||
/** initial size of the lookahead buffer */
|
||||
@@ -23,15 +24,16 @@ class _RegExLexer implements FlexLexer {
|
||||
|
||||
/** lexical states */
|
||||
public static final int EMBRACED = 4;
|
||||
public static final int PY_NAMED_GROUP = 16;
|
||||
public static final int PY_NAMED_GROUP_REF = 18;
|
||||
public static final int PY_NAMED_GROUP_REF = 20;
|
||||
public static final int QUOTED = 2;
|
||||
public static final int OPTIONS = 12;
|
||||
public static final int PY_COND_REF = 20;
|
||||
public static final int PY_COND_REF = 22;
|
||||
public static final int YYINITIAL = 0;
|
||||
public static final int NAMED_GROUP = 16;
|
||||
public static final int CLASS2 = 8;
|
||||
public static final int CLASS1 = 6;
|
||||
public static final int COMMENT = 14;
|
||||
public static final int QUOTED_NAMED_GROUP = 18;
|
||||
public static final int PROP = 10;
|
||||
|
||||
/**
|
||||
@@ -42,15 +44,15 @@ class _RegExLexer implements FlexLexer {
|
||||
*/
|
||||
private static final int ZZ_LEXSTATE[] = {
|
||||
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
|
||||
8, 8, 9, 9, 10, 10
|
||||
8, 8, 9, 9, 10, 10, 11, 11
|
||||
};
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
*/
|
||||
private static final String ZZ_CMAP_PACKED =
|
||||
"\10\0\2\52\1\13\1\0\1\52\1\61\22\0\1\45\1\56\1\0"+
|
||||
"\1\60\1\15\1\0\1\51\1\0\1\4\1\5\1\17\1\20\1\50"+
|
||||
"\10\0\2\52\1\13\1\0\1\52\1\62\22\0\1\45\1\56\1\0"+
|
||||
"\1\60\1\15\1\0\1\51\1\61\1\4\1\5\1\17\1\20\1\50"+
|
||||
"\1\43\1\3\1\0\1\2\7\42\2\1\1\53\1\0\1\57\1\55"+
|
||||
"\1\54\1\16\1\0\1\24\1\24\1\30\1\27\1\37\1\35\1\25"+
|
||||
"\1\44\1\32\6\44\1\34\1\36\1\44\1\26\3\44\1\26\1\26"+
|
||||
@@ -128,20 +130,20 @@ class _RegExLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ACTION = zzUnpackAction();
|
||||
|
||||
private static final String ZZ_ACTION_PACKED_0 =
|
||||
"\6\0\1\1\1\2\3\0\1\3\1\4\1\5\1\6"+
|
||||
"\6\0\1\1\1\2\4\0\1\3\1\4\1\5\1\6"+
|
||||
"\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16"+
|
||||
"\1\17\1\20\1\21\1\22\1\23\1\3\1\24\1\25"+
|
||||
"\1\26\1\27\1\30\1\31\1\32\1\33\1\34\1\3"+
|
||||
"\1\35\1\36\1\35\1\37\1\40\1\1\1\41\1\42"+
|
||||
"\1\2\1\43\1\44\1\45\1\46\1\47\1\50\1\51"+
|
||||
"\1\52\1\53\1\54\1\55\2\56\1\57\1\11\1\60"+
|
||||
"\1\61\1\62\1\63\1\64\1\65\1\0\1\66\1\67"+
|
||||
"\1\70\2\0\1\71\1\72\2\61\2\62\1\73\1\74"+
|
||||
"\1\75\1\76\1\0\1\71\1\61\1\77\2\62\1\100"+
|
||||
"\1\71\3\62\1\101";
|
||||
"\1\52\1\53\1\54\1\55\1\56\2\57\1\60\1\11"+
|
||||
"\1\61\1\62\1\63\1\64\1\65\1\66\1\0\1\67"+
|
||||
"\1\70\1\71\1\72\1\0\1\73\1\74\1\75\2\62"+
|
||||
"\2\63\1\76\1\77\1\100\1\101\1\0\1\74\1\62"+
|
||||
"\1\102\2\63\1\103\1\74\3\63\1\104";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[97];
|
||||
int [] result = new int[100];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -166,22 +168,22 @@ class _RegExLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
|
||||
|
||||
private static final String ZZ_ROWMAP_PACKED_0 =
|
||||
"\0\0\0\62\0\144\0\226\0\310\0\372\0\u012c\0\u015e"+
|
||||
"\0\u0190\0\u01c2\0\u01f4\0\u0226\0\u0226\0\u0258\0\u0226\0\u0226"+
|
||||
"\0\u028a\0\u02bc\0\u0226\0\u0226\0\u0226\0\u0226\0\u0226\0\u0226"+
|
||||
"\0\u0226\0\u0226\0\u0226\0\u0226\0\u02ee\0\u0226\0\u0320\0\u0226"+
|
||||
"\0\u0352\0\u0226\0\u0226\0\u0226\0\u0226\0\u0226\0\u0384\0\u0226"+
|
||||
"\0\u0226\0\u028a\0\u0226\0\u0226\0\u03b6\0\u03e8\0\u0226\0\u0226"+
|
||||
"\0\u0226\0\u041a\0\u0226\0\u0226\0\u044c\0\u047e\0\u0226\0\u0226"+
|
||||
"\0\u0226\0\u0226\0\u0226\0\u0226\0\u04b0\0\u0226\0\u0226\0\u0226"+
|
||||
"\0\u04e2\0\u0514\0\u0226\0\u0226\0\u0226\0\u0546\0\u0226\0\u0226"+
|
||||
"\0\u0226\0\u0578\0\u05aa\0\u05dc\0\u0226\0\u060e\0\u0640\0\u0672"+
|
||||
"\0\u06a4\0\u0226\0\u0226\0\u0226\0\u0226\0\u06d6\0\u0708\0\u0226"+
|
||||
"\0\u0226\0\u073a\0\u076c\0\u0226\0\u0226\0\u079e\0\u07d0\0\u0226"+
|
||||
"\0\u0226";
|
||||
"\0\0\0\63\0\146\0\231\0\314\0\377\0\u0132\0\u0165"+
|
||||
"\0\u0198\0\u01cb\0\u01fe\0\u0231\0\u0264\0\u0264\0\u0297\0\u0264"+
|
||||
"\0\u0264\0\u02ca\0\u02fd\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264"+
|
||||
"\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u0330\0\u0264\0\u0363"+
|
||||
"\0\u0264\0\u0396\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u03c9"+
|
||||
"\0\u0264\0\u0264\0\u02ca\0\u0264\0\u0264\0\u03fc\0\u042f\0\u0264"+
|
||||
"\0\u0264\0\u0264\0\u0264\0\u0462\0\u0264\0\u0264\0\u0495\0\u04c8"+
|
||||
"\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u0264\0\u04fb\0\u0264"+
|
||||
"\0\u0264\0\u0264\0\u052e\0\u0561\0\u0264\0\u0264\0\u0264\0\u0594"+
|
||||
"\0\u0264\0\u0264\0\u0264\0\u05c7\0\u05fa\0\u0264\0\u062d\0\u0264"+
|
||||
"\0\u0660\0\u0693\0\u06c6\0\u06f9\0\u0264\0\u0264\0\u0264\0\u0264"+
|
||||
"\0\u072c\0\u075f\0\u0264\0\u0264\0\u0792\0\u07c5\0\u0264\0\u0264"+
|
||||
"\0\u07f8\0\u082b\0\u0264\0\u0264";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[97];
|
||||
int [] result = new int[100];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -204,46 +206,47 @@ class _RegExLexer implements FlexLexer {
|
||||
private static final int [] ZZ_TRANS = zzUnpackTrans();
|
||||
|
||||
private static final String ZZ_TRANS_PACKED_0 =
|
||||
"\3\14\1\15\1\16\1\17\1\20\1\14\1\21\1\14"+
|
||||
"\1\22\1\23\1\24\1\25\1\26\1\27\1\30\1\31"+
|
||||
"\21\14\1\32\1\14\1\33\4\14\1\23\5\14\1\34"+
|
||||
"\1\23\12\14\1\35\1\0\46\14\1\36\2\37\4\36"+
|
||||
"\1\40\12\36\20\41\1\37\1\36\1\41\2\36\1\37"+
|
||||
"\1\42\11\36\11\43\1\44\1\43\1\0\46\43\6\14"+
|
||||
"\1\20\1\14\1\21\1\45\1\22\1\46\1\24\26\14"+
|
||||
"\1\32\5\14\1\47\1\46\6\14\1\46\6\50\1\51"+
|
||||
"\1\50\1\52\1\50\1\22\47\50\5\53\1\54\14\53"+
|
||||
"\20\55\1\53\1\56\1\55\6\53\1\57\6\53\13\10"+
|
||||
"\1\60\45\10\1\60\22\0\20\41\2\0\1\41\7\0"+
|
||||
"\1\61\5\0\5\53\1\54\14\53\20\41\2\53\1\41"+
|
||||
"\16\53\2\37\2\53\1\54\14\53\20\41\1\37\1\53"+
|
||||
"\1\41\2\53\1\37\12\53\100\0\1\62\54\0\1\63"+
|
||||
"\50\0\1\64\1\65\1\66\4\67\1\64\1\67\1\64"+
|
||||
"\1\67\1\70\6\67\2\71\2\72\2\73\1\74\1\75"+
|
||||
"\1\74\2\76\1\77\1\100\1\77\1\101\1\102\1\65"+
|
||||
"\1\67\1\77\1\70\4\64\1\70\6\64\1\70\37\0"+
|
||||
"\1\103\23\0\2\37\37\0\1\37\4\0\1\37\13\0"+
|
||||
"\2\41\17\0\21\41\1\0\1\41\1\0\2\41\63\0"+
|
||||
"\1\104\32\0\20\55\2\0\1\55\37\0\20\56\2\0"+
|
||||
"\1\56\21\0\1\105\27\0\1\106\16\0\2\107\1\110"+
|
||||
"\1\111\1\112\1\113\2\0\2\65\37\0\1\65\21\0"+
|
||||
"\1\114\37\0\1\114\17\0\62\115\1\116\2\117\20\116"+
|
||||
"\2\117\2\116\3\117\3\116\1\117\1\116\1\117\2\116"+
|
||||
"\1\117\17\116\1\120\2\121\20\120\2\121\2\120\3\121"+
|
||||
"\3\120\1\121\1\120\1\121\2\120\1\121\17\120\55\0"+
|
||||
"\1\122\1\0\1\123\57\0\1\124\1\125\3\0\5\126"+
|
||||
"\1\0\54\126\2\0\1\127\37\0\1\127\17\0\63\130"+
|
||||
"\2\131\20\130\2\131\2\130\3\131\3\130\1\131\1\130"+
|
||||
"\1\131\2\130\1\131\17\130\63\132\2\133\20\132\2\133"+
|
||||
"\2\132\3\133\3\132\1\133\1\132\1\133\2\132\1\133"+
|
||||
"\17\132\5\126\1\134\54\126\2\0\1\135\37\0\1\135"+
|
||||
"\17\0\63\136\2\137\20\136\2\137\2\136\3\137\3\136"+
|
||||
"\1\137\1\136\1\137\2\136\1\137\17\136\63\140\2\141"+
|
||||
"\20\140\2\141\2\140\3\141\3\140\1\141\1\140\1\141"+
|
||||
"\2\140\1\141\17\140";
|
||||
"\3\15\1\16\1\17\1\20\1\21\1\15\1\22\1\15"+
|
||||
"\1\23\1\24\1\25\1\26\1\27\1\30\1\31\1\32"+
|
||||
"\21\15\1\33\1\15\1\34\4\15\1\24\5\15\1\35"+
|
||||
"\1\15\1\24\12\15\1\36\1\0\47\15\1\37\2\40"+
|
||||
"\4\37\1\41\12\37\20\42\1\40\1\37\1\42\2\37"+
|
||||
"\1\40\1\43\12\37\11\44\1\45\1\44\1\0\47\44"+
|
||||
"\6\15\1\21\1\15\1\22\1\46\1\23\1\47\1\25"+
|
||||
"\26\15\1\33\5\15\1\50\1\47\7\15\1\47\6\51"+
|
||||
"\1\52\1\51\1\53\1\51\1\23\50\51\5\54\1\55"+
|
||||
"\14\54\20\56\1\54\1\57\1\56\6\54\1\60\7\54"+
|
||||
"\13\10\1\61\46\10\1\61\22\54\20\42\2\54\1\42"+
|
||||
"\7\54\1\62\30\54\20\42\2\54\1\42\14\54\1\63"+
|
||||
"\6\54\1\55\14\54\20\42\2\54\1\42\17\54\2\40"+
|
||||
"\2\54\1\55\14\54\20\42\1\40\1\54\1\42\2\54"+
|
||||
"\1\40\13\54\101\0\1\64\55\0\1\65\51\0\1\66"+
|
||||
"\1\67\1\70\4\71\1\66\1\71\1\66\1\71\1\72"+
|
||||
"\6\71\2\73\2\74\2\75\1\76\1\77\1\76\2\100"+
|
||||
"\1\101\1\102\1\101\1\103\1\104\1\67\1\71\1\101"+
|
||||
"\1\72\4\66\1\72\7\66\1\72\37\0\1\105\24\0"+
|
||||
"\2\40\37\0\1\40\4\0\1\40\14\0\2\42\17\0"+
|
||||
"\21\42\1\0\1\42\1\0\2\42\64\0\1\106\33\0"+
|
||||
"\20\56\2\0\1\56\40\0\20\57\2\0\1\57\22\0"+
|
||||
"\1\107\27\0\1\110\16\0\2\111\1\112\1\113\1\114"+
|
||||
"\1\115\1\116\2\0\2\67\37\0\1\67\22\0\1\117"+
|
||||
"\37\0\1\117\20\0\63\120\1\121\2\122\20\121\2\122"+
|
||||
"\2\121\3\122\3\121\1\122\1\121\1\122\2\121\1\122"+
|
||||
"\20\121\1\123\2\124\20\123\2\124\2\123\3\124\3\123"+
|
||||
"\1\124\1\123\1\124\2\123\1\124\20\123\55\0\1\125"+
|
||||
"\1\0\1\126\60\0\1\127\1\130\4\0\5\131\1\0"+
|
||||
"\55\131\2\0\1\132\37\0\1\132\20\0\64\133\2\134"+
|
||||
"\20\133\2\134\2\133\3\134\3\133\1\134\1\133\1\134"+
|
||||
"\2\133\1\134\20\133\64\135\2\136\20\135\2\136\2\135"+
|
||||
"\3\136\3\135\1\136\1\135\1\136\2\135\1\136\20\135"+
|
||||
"\5\131\1\137\55\131\2\0\1\140\37\0\1\140\20\0"+
|
||||
"\64\141\2\142\20\141\2\142\2\141\3\142\3\141\1\142"+
|
||||
"\1\141\1\142\2\141\1\142\20\141\64\143\2\144\20\143"+
|
||||
"\2\144\2\143\3\144\3\143\1\144\1\143\1\144\2\143"+
|
||||
"\1\144\20\143";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[2050];
|
||||
int [] result = new int[2142];
|
||||
int offset = 0;
|
||||
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -284,15 +287,15 @@ class _RegExLexer implements FlexLexer {
|
||||
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
|
||||
|
||||
private static final String ZZ_ATTRIBUTE_PACKED_0 =
|
||||
"\6\0\2\1\3\0\2\11\1\1\2\11\2\1\12\11"+
|
||||
"\6\0\2\1\4\0\2\11\1\1\2\11\2\1\12\11"+
|
||||
"\1\1\1\11\1\1\1\11\1\1\5\11\1\1\2\11"+
|
||||
"\1\1\2\11\2\1\3\11\1\1\2\11\2\1\6\11"+
|
||||
"\1\1\3\11\2\1\3\11\1\0\3\11\2\0\1\1"+
|
||||
"\1\11\4\1\4\11\1\0\1\1\2\11\2\1\2\11"+
|
||||
"\2\1\2\11";
|
||||
"\1\1\2\11\2\1\4\11\1\1\2\11\2\1\6\11"+
|
||||
"\1\1\3\11\2\1\3\11\1\0\3\11\1\1\1\0"+
|
||||
"\1\11\1\1\1\11\4\1\4\11\1\0\1\1\2\11"+
|
||||
"\2\1\2\11\2\1\2\11";
|
||||
|
||||
private static int [] zzUnpackAttribute() {
|
||||
int [] result = new int[97];
|
||||
int [] result = new int[100];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
@@ -648,257 +651,269 @@ class _RegExLexer implements FlexLexer {
|
||||
case 7:
|
||||
{ if (yystate() != CLASS2) yypushstate(EMBRACED); return RegExpTT.LBRACE;
|
||||
}
|
||||
case 66: break;
|
||||
case 69: break;
|
||||
case 6:
|
||||
{ return RegExpTT.GROUP_END;
|
||||
}
|
||||
case 67: break;
|
||||
case 37:
|
||||
case 70: break;
|
||||
case 38:
|
||||
// lookahead expression with fixed base length
|
||||
zzMarkedPos = zzStartRead + 1;
|
||||
{ yypushstate(CLASS1); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 68: break;
|
||||
case 71: break;
|
||||
case 14:
|
||||
{ return RegExpTT.STAR;
|
||||
}
|
||||
case 69: break;
|
||||
case 41:
|
||||
case 72: break;
|
||||
case 42:
|
||||
{ return RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 70: break;
|
||||
case 73: break;
|
||||
case 28:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 71: break;
|
||||
case 42:
|
||||
case 74: break;
|
||||
case 43:
|
||||
{ return commentMode ? RegExpTT.CHARACTER : RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 72: break;
|
||||
case 38:
|
||||
case 75: break;
|
||||
case 39:
|
||||
{ return RegExpTT.REDUNDANT_ESCAPE;
|
||||
}
|
||||
case 73: break;
|
||||
case 76: break;
|
||||
case 24:
|
||||
{ return RegExpTT.COMMA;
|
||||
}
|
||||
case 74: break;
|
||||
case 61:
|
||||
case 77: break;
|
||||
case 58:
|
||||
{ yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP;
|
||||
}
|
||||
case 78: break;
|
||||
case 64:
|
||||
{ return RegExpTT.POS_LOOKBEHIND;
|
||||
}
|
||||
case 75: break;
|
||||
case 40:
|
||||
case 79: break;
|
||||
case 41:
|
||||
{ return RegExpTT.BAD_OCT_VALUE;
|
||||
}
|
||||
case 76: break;
|
||||
case 80: break;
|
||||
case 10:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CTRL_CHARACTER;
|
||||
}
|
||||
case 77: break;
|
||||
case 81: break;
|
||||
case 30:
|
||||
{ yypopstate(); yypushstate(EMBRACED); return RegExpTT.LBRACE;
|
||||
}
|
||||
case 78: break;
|
||||
case 50:
|
||||
case 82: break;
|
||||
case 51:
|
||||
{ return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN;
|
||||
}
|
||||
case 79: break;
|
||||
case 62:
|
||||
case 83: break;
|
||||
case 65:
|
||||
{ return RegExpTT.NEG_LOOKBEHIND;
|
||||
}
|
||||
case 80: break;
|
||||
case 65:
|
||||
case 84: break;
|
||||
case 68:
|
||||
{ return RegExpTT.UNICODE_CHAR;
|
||||
}
|
||||
case 81: break;
|
||||
case 58:
|
||||
case 85: break;
|
||||
case 61:
|
||||
{ if (xmlSchemaMode) { yypushback(1); return RegExpTT.CHAR_CLASS; } else return RegExpTT.CTRL;
|
||||
}
|
||||
case 82: break;
|
||||
case 36:
|
||||
case 86: break;
|
||||
case 37:
|
||||
{ yybegin(OPTIONS); return RegExpTT.SET_OPTIONS;
|
||||
}
|
||||
case 83: break;
|
||||
case 87: break;
|
||||
case 12:
|
||||
{ return RegExpTT.DOLLAR;
|
||||
}
|
||||
case 84: break;
|
||||
case 51:
|
||||
case 88: break;
|
||||
case 52:
|
||||
{ yypopstate(); return RegExpTT.QUOTE_END;
|
||||
}
|
||||
case 85: break;
|
||||
case 55:
|
||||
case 89: break;
|
||||
case 56:
|
||||
{ return RegExpTT.POS_LOOKAHEAD;
|
||||
}
|
||||
case 86: break;
|
||||
case 90: break;
|
||||
case 22:
|
||||
{ yypopstate(); return RegExpTT.RBRACE;
|
||||
}
|
||||
case 87: break;
|
||||
case 91: break;
|
||||
case 3:
|
||||
{ return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 88: break;
|
||||
case 56:
|
||||
case 92: break;
|
||||
case 57:
|
||||
{ return RegExpTT.NEG_LOOKAHEAD;
|
||||
}
|
||||
case 89: break;
|
||||
case 43:
|
||||
case 93: break;
|
||||
case 44:
|
||||
{ return RegExpTT.ESC_CTRL_CHARACTER;
|
||||
}
|
||||
case 90: break;
|
||||
case 94: break;
|
||||
case 23:
|
||||
{ return RegExpTT.NAME;
|
||||
}
|
||||
case 91: break;
|
||||
case 52:
|
||||
case 95: break;
|
||||
case 53:
|
||||
{ return RegExpTT.ANDAND;
|
||||
}
|
||||
case 92: break;
|
||||
case 96: break;
|
||||
case 13:
|
||||
{ return RegExpTT.QUEST;
|
||||
}
|
||||
case 93: break;
|
||||
case 45:
|
||||
case 97: break;
|
||||
case 46:
|
||||
{ return RegExpTT.CHAR_CLASS;
|
||||
}
|
||||
case 94: break;
|
||||
case 98: break;
|
||||
case 17:
|
||||
{ return RegExpTT.MINUS;
|
||||
}
|
||||
case 95: break;
|
||||
case 64:
|
||||
case 99: break;
|
||||
case 67:
|
||||
{ return RegExpTT.COMMENT;
|
||||
}
|
||||
case 96: break;
|
||||
case 39:
|
||||
case 100: break;
|
||||
case 40:
|
||||
{ return yystate() != CLASS2 ? RegExpTT.BACKREF : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 97: break;
|
||||
case 101: break;
|
||||
case 16:
|
||||
{ return RegExpTT.UNION;
|
||||
}
|
||||
case 98: break;
|
||||
case 46:
|
||||
case 102: break;
|
||||
case 47:
|
||||
{ if (xmlSchemaMode) return RegExpTT.CHAR_CLASS; else return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
|
||||
}
|
||||
case 99: break;
|
||||
case 57:
|
||||
case 103: break;
|
||||
case 60:
|
||||
{ return RegExpTT.OCT_CHAR;
|
||||
}
|
||||
case 100: break;
|
||||
case 104: break;
|
||||
case 4:
|
||||
{ return RegExpTT.DOT;
|
||||
}
|
||||
case 101: break;
|
||||
case 105: break;
|
||||
case 32:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.GROUP_END;
|
||||
}
|
||||
case 102: break;
|
||||
case 106: break;
|
||||
case 21:
|
||||
{ return RegExpTT.NUMBER;
|
||||
}
|
||||
case 103: break;
|
||||
case 107: break;
|
||||
case 35:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.GT;
|
||||
}
|
||||
case 104: break;
|
||||
case 53:
|
||||
case 108: break;
|
||||
case 59:
|
||||
{ yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP;
|
||||
}
|
||||
case 109: break;
|
||||
case 54:
|
||||
{ yybegin(PY_COND_REF); return RegExpTT.PYTHON_COND_REF;
|
||||
}
|
||||
case 105: break;
|
||||
case 47:
|
||||
case 110: break;
|
||||
case 48:
|
||||
{ yypushstate(PROP); return RegExpTT.PROPERTY;
|
||||
}
|
||||
case 106: break;
|
||||
case 111: break;
|
||||
case 18:
|
||||
{ return commentMode ? com.intellij.psi.TokenType.WHITE_SPACE : RegExpTT.CHARACTER;
|
||||
}
|
||||
case 107: break;
|
||||
case 112: break;
|
||||
case 33:
|
||||
{ handleOptions(); return RegExpTT.OPTIONS_OFF;
|
||||
}
|
||||
case 108: break;
|
||||
case 113: break;
|
||||
case 34:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.COLON;
|
||||
}
|
||||
case 109: break;
|
||||
case 114: break;
|
||||
case 25:
|
||||
{ assert false : yytext();
|
||||
}
|
||||
case 110: break;
|
||||
case 59:
|
||||
case 115: break;
|
||||
case 62:
|
||||
{ yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF;
|
||||
}
|
||||
case 111: break;
|
||||
case 116: break;
|
||||
case 27:
|
||||
{ yypopstate(); return RegExpTT.CLASS_END;
|
||||
}
|
||||
case 112: break;
|
||||
case 117: break;
|
||||
case 11:
|
||||
{ return RegExpTT.CARET;
|
||||
}
|
||||
case 113: break;
|
||||
case 118: break;
|
||||
case 1:
|
||||
{ handleOptions(); return RegExpTT.OPTIONS_ON;
|
||||
}
|
||||
case 114: break;
|
||||
case 119: break;
|
||||
case 29:
|
||||
{ yypopstate(); yypushback(1);
|
||||
}
|
||||
case 115: break;
|
||||
case 44:
|
||||
case 120: break;
|
||||
case 45:
|
||||
{ return yystate() != CLASS2 ? RegExpTT.BOUNDARY : RegExpTT.ESC_CHARACTER;
|
||||
}
|
||||
case 116: break;
|
||||
case 121: break;
|
||||
case 63:
|
||||
{ yybegin(NAMED_GROUP); return RegExpTT.PYTHON_NAMED_GROUP;
|
||||
}
|
||||
case 122: break;
|
||||
case 19:
|
||||
{ if (commentMode) { yypushstate(COMMENT); return RegExpTT.COMMENT; } else return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 117: break;
|
||||
case 63:
|
||||
case 123: break;
|
||||
case 66:
|
||||
{ return RegExpTT.HEX_CHAR;
|
||||
}
|
||||
case 118: break;
|
||||
case 60:
|
||||
{ yybegin(PY_NAMED_GROUP); return RegExpTT.PYTHON_NAMED_GROUP;
|
||||
}
|
||||
case 119: break;
|
||||
case 124: break;
|
||||
case 5:
|
||||
{ return RegExpTT.GROUP_BEGIN;
|
||||
}
|
||||
case 120: break;
|
||||
case 125: break;
|
||||
case 8:
|
||||
{ yypushstate(CLASS2); return RegExpTT.CLASS_BEGIN;
|
||||
}
|
||||
case 121: break;
|
||||
case 54:
|
||||
case 126: break;
|
||||
case 55:
|
||||
{ return RegExpTT.NON_CAPT_GROUP;
|
||||
}
|
||||
case 122: break;
|
||||
case 127: break;
|
||||
case 9:
|
||||
{ return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN;
|
||||
}
|
||||
case 123: break;
|
||||
case 49:
|
||||
case 128: break;
|
||||
case 36:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.QUOTE;
|
||||
}
|
||||
case 129: break;
|
||||
case 50:
|
||||
{ return RegExpTT.BAD_HEX_VALUE;
|
||||
}
|
||||
case 124: break;
|
||||
case 130: break;
|
||||
case 2:
|
||||
{ yypopstate(); return RegExpTT.COMMENT;
|
||||
}
|
||||
case 125: break;
|
||||
case 48:
|
||||
case 131: break;
|
||||
case 49:
|
||||
{ yypushstate(QUOTED); return RegExpTT.QUOTE_BEGIN;
|
||||
}
|
||||
case 126: break;
|
||||
case 132: break;
|
||||
case 26:
|
||||
{ yybegin(CLASS2); return RegExpTT.CHARACTER;
|
||||
}
|
||||
case 127: break;
|
||||
case 133: break;
|
||||
case 15:
|
||||
{ return RegExpTT.PLUS;
|
||||
}
|
||||
case 128: break;
|
||||
case 134: break;
|
||||
case 20:
|
||||
{ if (allowDanglingMetacharacters) {
|
||||
yypopstate(); yypushback(1);
|
||||
@@ -906,11 +921,11 @@ class _RegExLexer implements FlexLexer {
|
||||
return RegExpTT.BAD_CHARACTER;
|
||||
}
|
||||
}
|
||||
case 129: break;
|
||||
case 135: break;
|
||||
case 31:
|
||||
{ yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER;
|
||||
}
|
||||
case 130: break;
|
||||
case 136: break;
|
||||
default:
|
||||
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
|
||||
zzAtEOF = true;
|
||||
|
||||
@@ -18,15 +18,17 @@ package org.intellij.lang.regexp.psi;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface RegExpGroup extends RegExpAtom {
|
||||
boolean isCapturing();
|
||||
|
||||
boolean isSimple();
|
||||
boolean isCapturing();
|
||||
|
||||
@Nullable
|
||||
RegExpPattern getPattern();
|
||||
boolean isSimple();
|
||||
|
||||
boolean isPythonNamedGroup();
|
||||
@Nullable
|
||||
RegExpPattern getPattern();
|
||||
|
||||
@Nullable
|
||||
String getGroupName();
|
||||
boolean isPythonNamedGroup();
|
||||
|
||||
boolean isRubyNamedGroup();
|
||||
|
||||
@Nullable
|
||||
String getGroupName();
|
||||
}
|
||||
|
||||
@@ -24,38 +24,43 @@ import org.intellij.lang.regexp.psi.RegExpGroup;
|
||||
import org.intellij.lang.regexp.psi.RegExpPattern;
|
||||
|
||||
public class RegExpGroupImpl extends RegExpElementImpl implements RegExpGroup {
|
||||
public RegExpGroupImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
public RegExpGroupImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
public void accept(RegExpElementVisitor visitor) {
|
||||
visitor.visitRegExpGroup(this);
|
||||
}
|
||||
public void accept(RegExpElementVisitor visitor) {
|
||||
visitor.visitRegExpGroup(this);
|
||||
}
|
||||
|
||||
public boolean isCapturing() {
|
||||
final ASTNode node = getNode().getFirstChildNode();
|
||||
return node != null && node.getElementType() == RegExpTT.GROUP_BEGIN;
|
||||
}
|
||||
public boolean isCapturing() {
|
||||
final ASTNode node = getNode().getFirstChildNode();
|
||||
return node != null && node.getElementType() == RegExpTT.GROUP_BEGIN;
|
||||
}
|
||||
|
||||
public boolean isSimple() {
|
||||
final ASTNode node = getNode().getFirstChildNode();
|
||||
return node != null && (node.getElementType() == RegExpTT.GROUP_BEGIN || node.getElementType() == RegExpTT.NON_CAPT_GROUP);
|
||||
}
|
||||
public boolean isSimple() {
|
||||
final ASTNode node = getNode().getFirstChildNode();
|
||||
return node != null && (node.getElementType() == RegExpTT.GROUP_BEGIN || node.getElementType() == RegExpTT.NON_CAPT_GROUP);
|
||||
}
|
||||
|
||||
public RegExpPattern getPattern() {
|
||||
final ASTNode node = getNode().findChildByType(RegExpElementTypes.PATTERN);
|
||||
return node != null ? (RegExpPattern)node.getPsi() : null;
|
||||
}
|
||||
public RegExpPattern getPattern() {
|
||||
final ASTNode node = getNode().findChildByType(RegExpElementTypes.PATTERN);
|
||||
return node != null ? (RegExpPattern)node.getPsi() : null;
|
||||
}
|
||||
|
||||
public boolean isPythonNamedGroup() {
|
||||
return getNode().findChildByType(RegExpTT.PYTHON_NAMED_GROUP) != null;
|
||||
}
|
||||
public boolean isPythonNamedGroup() {
|
||||
return getNode().findChildByType(RegExpTT.PYTHON_NAMED_GROUP) != null;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
if (!isPythonNamedGroup()) {
|
||||
return null;
|
||||
}
|
||||
final ASTNode nameNode = getNode().findChildByType(RegExpTT.NAME);
|
||||
return nameNode != null ? nameNode.getText() : null;
|
||||
public boolean isRubyNamedGroup() {
|
||||
return getNode().findChildByType(RegExpTT.RUBY_NAMED_GROUP) != null ||
|
||||
getNode().findChildByType(RegExpTT.RUBY_QUOTED_NAMED_GROUP) != null;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
if (!isPythonNamedGroup()) {
|
||||
return null;
|
||||
}
|
||||
final ASTNode nameNode = getNode().findChildByType(RegExpTT.NAME);
|
||||
return nameNode != null ? nameNode.getText() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ import com.intellij.psi.StringEscapesTokenTypes;
|
||||
%state PROP
|
||||
%xstate OPTIONS
|
||||
%xstate COMMENT
|
||||
%xstate PY_NAMED_GROUP
|
||||
%xstate NAMED_GROUP
|
||||
%xstate QUOTED_NAMED_GROUP
|
||||
%xstate PY_NAMED_GROUP_REF
|
||||
%xstate PY_COND_REF
|
||||
|
||||
@@ -208,10 +209,13 @@ HEX_CHAR=[0-9a-fA-F]
|
||||
"(?<=" { return RegExpTT.POS_LOOKBEHIND; }
|
||||
"(?<!" { return RegExpTT.NEG_LOOKBEHIND; }
|
||||
"(?#" [^)]+ ")" { return RegExpTT.COMMENT; }
|
||||
"(?P<" { yybegin(PY_NAMED_GROUP); return RegExpTT.PYTHON_NAMED_GROUP; }
|
||||
"(?P<" { yybegin(NAMED_GROUP); return RegExpTT.PYTHON_NAMED_GROUP; }
|
||||
"(?P=" { yybegin(PY_NAMED_GROUP_REF); return RegExpTT.PYTHON_NAMED_GROUP_REF; }
|
||||
"(?(" { yybegin(PY_COND_REF); return RegExpTT.PYTHON_COND_REF; }
|
||||
|
||||
"(?<" { yybegin(NAMED_GROUP); return RegExpTT.RUBY_NAMED_GROUP; }
|
||||
"(?'" { yybegin(QUOTED_NAMED_GROUP); return RegExpTT.RUBY_QUOTED_NAMED_GROUP; }
|
||||
|
||||
"(?" { yybegin(OPTIONS); return RegExpTT.SET_OPTIONS; }
|
||||
}
|
||||
|
||||
@@ -225,9 +229,16 @@ HEX_CHAR=[0-9a-fA-F]
|
||||
{ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; }
|
||||
}
|
||||
|
||||
<PY_NAMED_GROUP> {
|
||||
<NAMED_GROUP> {
|
||||
[:letter:]([:letter:]|_|[:digit:])* { return RegExpTT.NAME; }
|
||||
">" { yybegin(YYINITIAL); return RegExpTT.GT; }
|
||||
{ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; }
|
||||
}
|
||||
|
||||
<QUOTED_NAMED_GROUP> {
|
||||
[:letter:]([:letter:]|_|[:digit:])* { return RegExpTT.NAME; }
|
||||
"'" { yybegin(YYINITIAL); return RegExpTT.QUOTE; }
|
||||
{ANY} { yybegin(YYINITIAL); return RegExpTT.BAD_CHARACTER; }
|
||||
}
|
||||
|
||||
<PY_NAMED_GROUP_REF> {
|
||||
|
||||
@@ -34,144 +34,152 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class RegExpAnnotator extends RegExpElementVisitor implements Annotator {
|
||||
private AnnotationHolder myHolder;
|
||||
private AnnotationHolder myHolder;
|
||||
|
||||
public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) {
|
||||
assert myHolder == null : "unsupported concurrent annotator invocation";
|
||||
try {
|
||||
myHolder = holder;
|
||||
psiElement.accept(this);
|
||||
} finally {
|
||||
myHolder = null;
|
||||
}
|
||||
public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) {
|
||||
assert myHolder == null : "unsupported concurrent annotator invocation";
|
||||
try {
|
||||
myHolder = holder;
|
||||
psiElement.accept(this);
|
||||
}
|
||||
finally {
|
||||
myHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpCharRange(RegExpCharRange range) {
|
||||
final RegExpCharRange.Endpoint from = range.getFrom();
|
||||
final RegExpCharRange.Endpoint to = range.getTo();
|
||||
final boolean a = from instanceof RegExpChar;
|
||||
final boolean b = to instanceof RegExpChar;
|
||||
if (a && b) {
|
||||
final Character t = ((RegExpChar)to).getValue();
|
||||
final Character f = ((RegExpChar)from).getValue();
|
||||
if (t != null && f != null) {
|
||||
if (t < f) {
|
||||
myHolder.createErrorAnnotation(range, "Illegal character range (to < from)");
|
||||
} else if (t == f) {
|
||||
myHolder.createWarningAnnotation(range, "Redundant character range");
|
||||
}
|
||||
public void visitRegExpCharRange(RegExpCharRange range) {
|
||||
final RegExpCharRange.Endpoint from = range.getFrom();
|
||||
final RegExpCharRange.Endpoint to = range.getTo();
|
||||
final boolean a = from instanceof RegExpChar;
|
||||
final boolean b = to instanceof RegExpChar;
|
||||
if (a && b) {
|
||||
final Character t = ((RegExpChar)to).getValue();
|
||||
final Character f = ((RegExpChar)from).getValue();
|
||||
if (t != null && f != null) {
|
||||
if (t < f) {
|
||||
myHolder.createErrorAnnotation(range, "Illegal character range (to < from)");
|
||||
}
|
||||
else if (t == f) {
|
||||
myHolder.createWarningAnnotation(range, "Redundant character range");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (a != b) {
|
||||
myHolder.createErrorAnnotation(range, "Character class (e.g. '\\\\w') may not be used inside character range");
|
||||
}
|
||||
else if (from.getText().equals(to.getText())) {
|
||||
myHolder.createWarningAnnotation(range, "Redundant character range");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpChar(final RegExpChar ch) {
|
||||
final Character value = ch.getValue();
|
||||
if (value == null) {
|
||||
switch (ch.getType()) {
|
||||
case CHAR:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal/unsupported escape sequence");
|
||||
break;
|
||||
case HEX:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal hexadecimal escape sequence");
|
||||
break;
|
||||
case OCT:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal octal escape sequence");
|
||||
break;
|
||||
case UNICODE:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal unicode escape sequence");
|
||||
break;
|
||||
case INVALID:
|
||||
// produces a parser error. already handled by IDEA and possibly suppressed by IntelliLang
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String text = ch.getUnescapedText();
|
||||
if (text.startsWith("\\") && isRedundantEscape(ch, text)) {
|
||||
final ASTNode astNode = ch.getNode().getFirstChildNode();
|
||||
if (astNode != null && astNode.getElementType() == RegExpTT.REDUNDANT_ESCAPE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(ch, "Redundant character escape");
|
||||
registerFix(a, new RemoveRedundantEscapeAction(ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRedundantEscape(RegExpChar ch, String text) {
|
||||
if (text.length() <= 1) return false;
|
||||
RegExpLanguageHost host = findRegExpHost(ch);
|
||||
if (host != null) {
|
||||
final char c = text.charAt(1);
|
||||
final boolean needsEscaping = host.characterNeedsEscaping(c);
|
||||
return !needsEscaping;
|
||||
}
|
||||
else {
|
||||
return !("\\]".equals(text) || "\\}".equals(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RegExpLanguageHost findRegExpHost(PsiElement element) {
|
||||
PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
|
||||
if (host instanceof RegExpLanguageHost) {
|
||||
return (RegExpLanguageHost)host;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visitRegExpProperty(RegExpProperty property) {
|
||||
final ASTNode category = property.getCategoryNode();
|
||||
if (category != null && !RegExpPropertyImpl.isValidCategory(category.getText())) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(category, "Unknown character category");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpBackref(final RegExpBackref backref) {
|
||||
final RegExpGroup group = backref.resolve();
|
||||
if (group == null) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved backreference");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
else if (PsiTreeUtil.isAncestor(group, backref, true)) {
|
||||
myHolder.createWarningAnnotation(backref, "Backreference is nested into the capturing group it refers to");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpGroup(RegExpGroup group) {
|
||||
final RegExpPattern pattern = group.getPattern();
|
||||
if (pattern != null) {
|
||||
final RegExpBranch[] branches = pattern.getBranches();
|
||||
if (isEmpty(branches)) {
|
||||
// catches "()" as well as "(|)"
|
||||
myHolder.createWarningAnnotation(group, "Empty group");
|
||||
}
|
||||
else if (branches.length == 1) {
|
||||
final RegExpAtom[] atoms = branches[0].getAtoms();
|
||||
if (atoms.length == 1 && atoms[0] instanceof RegExpGroup) {
|
||||
if (group.isSimple()) {
|
||||
final RegExpGroup innerGroup = (RegExpGroup)atoms[0];
|
||||
if (group.isCapturing() == innerGroup.isCapturing()) {
|
||||
myHolder.createWarningAnnotation(group, "Redundant group nesting");
|
||||
}
|
||||
} else if (a != b) {
|
||||
myHolder.createErrorAnnotation(range, "Character class (e.g. '\\\\w') may not be used inside character range");
|
||||
} else if (from.getText().equals(to.getText())) {
|
||||
myHolder.createWarningAnnotation(range, "Redundant character range");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpChar(final RegExpChar ch) {
|
||||
final Character value = ch.getValue();
|
||||
if (value == null) {
|
||||
switch (ch.getType()) {
|
||||
case CHAR:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal/unsupported escape sequence");
|
||||
break;
|
||||
case HEX:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal hexadecimal escape sequence");
|
||||
break;
|
||||
case OCT:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal octal escape sequence");
|
||||
break;
|
||||
case UNICODE:
|
||||
myHolder.createErrorAnnotation(ch, "Illegal unicode escape sequence");
|
||||
break;
|
||||
case INVALID:
|
||||
// produces a parser error. already handled by IDEA and possibly suppressed by IntelliLang
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
final String text = ch.getUnescapedText();
|
||||
if (text.startsWith("\\") && isRedundantEscape(ch, text)) {
|
||||
final ASTNode astNode = ch.getNode().getFirstChildNode();
|
||||
if (astNode != null && astNode.getElementType() == RegExpTT.REDUNDANT_ESCAPE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(ch, "Redundant character escape");
|
||||
registerFix(a, new RemoveRedundantEscapeAction(ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRedundantEscape(RegExpChar ch, String text) {
|
||||
if (text.length() <= 1) return false;
|
||||
RegExpLanguageHost host = findRegExpHost(ch);
|
||||
if (host != null) {
|
||||
final char c = text.charAt(1);
|
||||
final boolean needsEscaping = host.characterNeedsEscaping(c);
|
||||
return !needsEscaping;
|
||||
}
|
||||
else {
|
||||
return!("\\]".equals(text) || "\\}".equals(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static RegExpLanguageHost findRegExpHost(PsiElement element) {
|
||||
PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
|
||||
if (host instanceof RegExpLanguageHost) {
|
||||
return (RegExpLanguageHost) host;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void visitRegExpProperty(RegExpProperty property) {
|
||||
final ASTNode category = property.getCategoryNode();
|
||||
if (category != null && !RegExpPropertyImpl.isValidCategory(category.getText())) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(category, "Unknown character category");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpBackref(final RegExpBackref backref) {
|
||||
final RegExpGroup group = backref.resolve();
|
||||
if (group == null) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(backref, "Unresolved backreference");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
} else if (PsiTreeUtil.isAncestor(group, backref, true)) {
|
||||
myHolder.createWarningAnnotation(backref, "Backreference is nested into the capturing group it refers to");
|
||||
}
|
||||
}
|
||||
|
||||
public void visitRegExpGroup(RegExpGroup group) {
|
||||
final RegExpPattern pattern = group.getPattern();
|
||||
if (pattern != null) {
|
||||
final RegExpBranch[] branches = pattern.getBranches();
|
||||
if (isEmpty(branches)) {
|
||||
// catches "()" as well as "(|)"
|
||||
myHolder.createWarningAnnotation(group, "Empty group");
|
||||
} else if (branches.length == 1) {
|
||||
final RegExpAtom[] atoms = branches[0].getAtoms();
|
||||
if (atoms.length == 1 && atoms[0] instanceof RegExpGroup) {
|
||||
if (group.isSimple()) {
|
||||
final RegExpGroup innerGroup = (RegExpGroup)atoms[0];
|
||||
if (group.isCapturing() == innerGroup.isCapturing()) {
|
||||
myHolder.createWarningAnnotation(group, "Redundant group nesting");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (group.isPythonNamedGroup()) {
|
||||
RegExpLanguageHost host = findRegExpHost(group);
|
||||
if (host == null || !host.supportsPythonNamedGroups()) {
|
||||
myHolder.createErrorAnnotation(group, "This named group syntax is not supported");
|
||||
}
|
||||
}
|
||||
if (group.isPythonNamedGroup() || group.isRubyNamedGroup()) {
|
||||
RegExpLanguageHost host = findRegExpHost(group);
|
||||
if (host == null || (group.isPythonNamedGroup() && !host.supportsPythonNamedGroups()) ||
|
||||
(group.isRubyNamedGroup() && !host.supportsRubyNamedGroups())) {
|
||||
myHolder.createErrorAnnotation(group, "This named group syntax is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRegExpPyNamedGroupRef(RegExpPyNamedGroupRef groupRef) {
|
||||
@@ -182,85 +190,91 @@ public final class RegExpAnnotator extends RegExpElementVisitor implements Annot
|
||||
}
|
||||
final RegExpGroup group = groupRef.resolve();
|
||||
if (group == null) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved backreference");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
} else if (PsiTreeUtil.isAncestor(group, groupRef, true)) {
|
||||
final Annotation a = myHolder.createErrorAnnotation(groupRef, "Unresolved backreference");
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
else if (PsiTreeUtil.isAncestor(group, groupRef, true)) {
|
||||
myHolder.createWarningAnnotation(groupRef, "Group reference is nested into the named group it refers to");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitComment(PsiComment comment) {
|
||||
if (comment.getText().startsWith("(?#")) {
|
||||
RegExpLanguageHost host = findRegExpHost(comment);
|
||||
if (host == null || !host.supportsPerl5EmbeddedComments()) {
|
||||
myHolder.createErrorAnnotation(comment, "Embedded comments are not supported");
|
||||
}
|
||||
}
|
||||
public void visitComment(PsiComment comment) {
|
||||
if (comment.getText().startsWith("(?#")) {
|
||||
RegExpLanguageHost host = findRegExpHost(comment);
|
||||
if (host == null || !host.supportsPerl5EmbeddedComments()) {
|
||||
myHolder.createErrorAnnotation(comment, "Embedded comments are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRegExpPyCondRef(RegExpPyCondRef condRef) {
|
||||
RegExpLanguageHost host = findRegExpHost(condRef);
|
||||
if (host == null || !host.supportsPythonConditionalRefs()) {
|
||||
myHolder.createErrorAnnotation(condRef, "Conditional references are not supported");
|
||||
myHolder.createErrorAnnotation(condRef, "Conditional references are not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEmpty(RegExpBranch[] branches) {
|
||||
for (RegExpBranch branch : branches) {
|
||||
if (branch.getAtoms().length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
for (RegExpBranch branch : branches) {
|
||||
if (branch.getAtoms().length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void visitRegExpQuantifier(RegExpQuantifier quantifier) {
|
||||
final RegExpQuantifier.Count count = quantifier.getCount();
|
||||
if (!(count instanceof RegExpQuantifier.SimpleCount)) {
|
||||
final int min = count.getMin();
|
||||
final int max = count.getMax();
|
||||
if (max < min) {
|
||||
myHolder.createErrorAnnotation(quantifier, "Illegal repetition range");
|
||||
} else if (max == min) {
|
||||
if (max == 1) { // TODO: is this safe when reluctant or possesive modifier is present?
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Single repetition");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, null));
|
||||
} else {
|
||||
final ASTNode node = quantifier.getNode();
|
||||
if (node.findChildByType(RegExpTT.COMMA) != null) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Fixed repetition range");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "{" + max + "}"));
|
||||
}
|
||||
}
|
||||
} else if (min == 0 && max == 1) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '?'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "?"));
|
||||
} else if (min == 0 && max == Integer.MAX_VALUE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '*'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "*"));
|
||||
} else if (min == 1 && max == Integer.MAX_VALUE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '+'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "+"));
|
||||
}
|
||||
public void visitRegExpQuantifier(RegExpQuantifier quantifier) {
|
||||
final RegExpQuantifier.Count count = quantifier.getCount();
|
||||
if (!(count instanceof RegExpQuantifier.SimpleCount)) {
|
||||
final int min = count.getMin();
|
||||
final int max = count.getMax();
|
||||
if (max < min) {
|
||||
myHolder.createErrorAnnotation(quantifier, "Illegal repetition range");
|
||||
}
|
||||
else if (max == min) {
|
||||
if (max == 1) { // TODO: is this safe when reluctant or possesive modifier is present?
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Single repetition");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, null));
|
||||
}
|
||||
if (quantifier.getType() == RegExpQuantifier.Type.POSSESSIVE) {
|
||||
RegExpLanguageHost host = findRegExpHost(quantifier);
|
||||
if (host != null && !host.supportsPossessiveQuantifiers()) {
|
||||
myHolder.createErrorAnnotation(quantifier, "Nested quantifier in regexp");
|
||||
}
|
||||
else {
|
||||
final ASTNode node = quantifier.getNode();
|
||||
if (node.findChildByType(RegExpTT.COMMA) != null) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Fixed repetition range");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "{" + max + "}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (min == 0 && max == 1) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '?'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "?"));
|
||||
}
|
||||
else if (min == 0 && max == Integer.MAX_VALUE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '*'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "*"));
|
||||
}
|
||||
else if (min == 1 && max == Integer.MAX_VALUE) {
|
||||
final Annotation a = myHolder.createInformationAnnotation(quantifier, "Repetition range replaceable by '+'");
|
||||
registerFix(a, new SimplifyQuantifierAction(quantifier, "+"));
|
||||
}
|
||||
}
|
||||
if (quantifier.getType() == RegExpQuantifier.Type.POSSESSIVE) {
|
||||
RegExpLanguageHost host = findRegExpHost(quantifier);
|
||||
if (host != null && !host.supportsPossessiveQuantifiers()) {
|
||||
myHolder.createErrorAnnotation(quantifier, "Nested quantifier in regexp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerFix(Annotation a, IntentionAction action) {
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.registerFix(action);
|
||||
}
|
||||
private static void registerFix(Annotation a, IntentionAction action) {
|
||||
if (a != null) {
|
||||
// IDEA-9381
|
||||
a.registerFix(action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -336,18 +336,23 @@ public class ClsMethodImpl extends ClsRepositoryPsiElement<PsiMethodStub> implem
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getNavigationElement() {
|
||||
public PsiMethod getSourceMirrorMethod() {
|
||||
PsiClass sourceClassMirror = ((ClsClassImpl)getParent()).getSourceMirrorClass();
|
||||
if (sourceClassMirror == null) return this;
|
||||
final PsiMethod[] methodsByName = sourceClassMirror.findMethodsByName(getName(), false);
|
||||
for (PsiMethod sourceMethod : methodsByName) {
|
||||
if (MethodSignatureUtil.areParametersErasureEqual(this, sourceMethod) && sourceMethod != this) {
|
||||
return sourceMethod.getNavigationElement();
|
||||
for (PsiMethod sourceMethod : sourceClassMirror.findMethodsByName(getName(), false)) {
|
||||
if (MethodSignatureUtil.areParametersErasureEqual(this, sourceMethod)) {
|
||||
return sourceMethod;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getNavigationElement() {
|
||||
final PsiMethod method = getSourceMirrorMethod();
|
||||
return method != this ? method.getNavigationElement() : this;
|
||||
}
|
||||
|
||||
public PsiTypeParameterList getTypeParameterList() {
|
||||
return getStub().findChildStubByType(JavaStubElementTypes.TYPE_PARAMETER_LIST).getPsi();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ClsParameterImpl extends ClsRepositoryPsiElement<PsiParameterStub>
|
||||
}
|
||||
|
||||
ClsMethodImpl method = (ClsMethodImpl)getDeclarationScope();
|
||||
PsiMethod sourceMethod = (PsiMethod)method.getNavigationElement();
|
||||
PsiMethod sourceMethod = method.getSourceMirrorMethod();
|
||||
if (sourceMethod == method) {
|
||||
final PsiParameterStubImpl parameterStub = (PsiParameterStubImpl) getStub();
|
||||
if (!parameterStub.isAutoGeneratedName()) {
|
||||
|
||||
@@ -40,6 +40,7 @@ public class RunContentDescriptor {
|
||||
* Used to hack {@link com.intellij.execution.runners.RestartAction}
|
||||
*/
|
||||
private Content myContent;
|
||||
private Runnable myRestarter;
|
||||
|
||||
public RunContentDescriptor(final ExecutionConsole executionConsole,
|
||||
final ProcessHandler processHandler, final JComponent component, final String displayName, final Icon icon) {
|
||||
@@ -108,4 +109,12 @@ public class RunContentDescriptor {
|
||||
public Content getAttachedContent() {
|
||||
return myContent;
|
||||
}
|
||||
|
||||
public void setRestarter(Runnable runnable) {
|
||||
myRestarter = runnable;
|
||||
}
|
||||
|
||||
public Runnable getRestarter() {
|
||||
return myRestarter;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ public class CompletionLookupArranger extends LookupArranger {
|
||||
|
||||
for (int i = 0; i < weight1.length; i++) {
|
||||
final Comparable w1 = weight1[i];
|
||||
final Comparable w2 = weight2[i];
|
||||
final Comparable w2 = i < weight2.length ? weight2[i]:null;
|
||||
if (w1 != null || w2 != null) {
|
||||
if (w1 == null) return 1;
|
||||
if (w2 == null) return -1;
|
||||
|
||||
+15
-7
@@ -22,6 +22,7 @@ import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
@@ -48,16 +49,27 @@ public class CustomTemplateCallback {
|
||||
private LiveTemplateBuilder.Marker myEndOffsetMarker;
|
||||
private final Map<Object, LiveTemplateBuilder.Marker> myCheckpoints = new HashMap<Object, LiveTemplateBuilder.Marker>();
|
||||
|
||||
private final boolean myInInjectedFragment;
|
||||
|
||||
private FileType myFileType;
|
||||
|
||||
private LiveTemplateBuilder myBuilder = new LiveTemplateBuilder();
|
||||
private int myOffset = 0;
|
||||
|
||||
public CustomTemplateCallback(Editor editor, PsiFile file) {
|
||||
myEditor = editor;
|
||||
myFile = file;
|
||||
myProject = file.getProject();
|
||||
myTemplateManager = TemplateManagerImpl.getInstance(myProject);
|
||||
|
||||
int caretOffset = editor.getCaretModel().getOffset();
|
||||
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
|
||||
PsiElement element = InjectedLanguageUtil.findElementAtNoCommit(file, caretOffset);
|
||||
|
||||
myFile = element != null ? element.getContainingFile() : file;
|
||||
|
||||
myInInjectedFragment = InjectedLanguageManager.getInstance(myProject).isInjectedFragment(myFile);
|
||||
myEditor = myInInjectedFragment ? InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, file) : editor;
|
||||
|
||||
fixInitialState();
|
||||
}
|
||||
|
||||
@@ -151,11 +163,6 @@ public class CustomTemplateCallback {
|
||||
}
|
||||
|
||||
public void startAllExpandedTemplates() {
|
||||
/*myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
|
||||
final CodeStyleManager style = CodeStyleManager.getInstance(myProject);
|
||||
if (myGlobalMarker != null) {
|
||||
style.reformatText(myFile, myGlobalMarker.getStartOffset(), myGlobalMarker.getEndOffset());
|
||||
}*/
|
||||
if (myBuilder.getText().length() == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -164,6 +171,7 @@ public class CustomTemplateCallback {
|
||||
myBuilder.insertVariableSegment(myOffset, TemplateImpl.END);
|
||||
}
|
||||
TemplateImpl template = myBuilder.buildTemplate();
|
||||
template.setToReformat(!myInInjectedFragment);
|
||||
myTemplateManager.startTemplate(myEditor, template, false, myBuilder.getPredefinedValues(), null);
|
||||
myBuilder = new LiveTemplateBuilder();
|
||||
myEndOffsetMarker = null;
|
||||
|
||||
@@ -74,7 +74,6 @@ public class LiveTemplateBuilder {
|
||||
last = occurence.myOffset;
|
||||
}
|
||||
template.addTextSegment(myText.substring(last));
|
||||
template.setToReformat(true);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ExecutionHelper {
|
||||
return;
|
||||
}
|
||||
for (final Exception exception : exceptionList) {
|
||||
String[] messages = new String[]{exception.getMessage()};
|
||||
String[] messages = StringUtil.splitByLines(exception.getMessage());
|
||||
if (messages.length == 0) messages = new String[]{"Unknown Error"};
|
||||
errorTreeView.addMessage(MessageCategory.ERROR, messages, file, -1, -1, null);
|
||||
}
|
||||
|
||||
-1
@@ -51,7 +51,6 @@ import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.RunCanceledByUserException;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.keymap.KeymapManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
@@ -57,6 +58,14 @@ public class RestartAction extends AnAction implements DumbAware {
|
||||
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
final DataContext dataContext = e.getDataContext();
|
||||
doRestart(dataContext);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
doRestart(DataManager.getInstance().getDataContext(myDescriptor.getComponent()));
|
||||
}
|
||||
|
||||
private void doRestart(final DataContext dataContext) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
|
||||
try {
|
||||
final ExecutionEnvironment old = myEnvironment;
|
||||
|
||||
@@ -199,6 +199,11 @@ public class RunContentBuilder implements LogConsoleManager, Disposable {
|
||||
final RestartAction restartAction = new RestartAction(myExecutor, myRunner, getProcessHandler(), myRerunIcon, contentDescriptor, myEnvironment);
|
||||
restartAction.registerShortcut(component);
|
||||
actionGroup.add(restartAction);
|
||||
contentDescriptor.setRestarter(new Runnable() {
|
||||
public void run() {
|
||||
restartAction.restart();
|
||||
}
|
||||
});
|
||||
|
||||
if (myExecutionResult instanceof DefaultExecutionResult) {
|
||||
final AnAction[] actions = ((DefaultExecutionResult)myExecutionResult).getRestartActions();
|
||||
|
||||
@@ -392,7 +392,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private static RunContentDescriptor getRunContentDescriptorByContent(final Content content) {
|
||||
public static RunContentDescriptor getRunContentDescriptorByContent(final Content content) {
|
||||
return content.getUserData(DESCRIPTOR_KEY);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ public abstract class ChooseByNameBase{
|
||||
protected final Project myProject;
|
||||
protected final ChooseByNameModel myModel;
|
||||
protected final String myInitialText;
|
||||
private boolean myPreselectInitialText;
|
||||
private final Reference<PsiElement> myContext;
|
||||
|
||||
protected Component myPreviouslyFocusedComponent;
|
||||
@@ -147,6 +148,14 @@ public abstract class ChooseByNameBase{
|
||||
myContext = new WeakReference<PsiElement>(context);
|
||||
}
|
||||
|
||||
public boolean isPreselectInitialText() {
|
||||
return myPreselectInitialText;
|
||||
}
|
||||
|
||||
public void setPreselectInitialText(boolean preselectInitialText) {
|
||||
myPreselectInitialText = preselectInitialText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tool area. The method may be called only before invoke.
|
||||
* @param toolArea a tool area component
|
||||
@@ -321,6 +330,9 @@ public abstract class ChooseByNameBase{
|
||||
myFuture = new ArrayList<Pair<String, Integer>>();
|
||||
myTextField = new MyTextField();
|
||||
myTextField.setText(myInitialText);
|
||||
if (myPreselectInitialText) {
|
||||
myTextField.select(0, myInitialText.length());
|
||||
}
|
||||
|
||||
final ActionMap actionMap = new ActionMap();
|
||||
actionMap.setParent(myTextField.getActionMap());
|
||||
|
||||
@@ -40,6 +40,9 @@ public class ChooseByNamePopup extends ChooseByNameBase implements ChooseByNameP
|
||||
private ChooseByNamePopup(final Project project, final ChooseByNameModel model, final ChooseByNamePopup oldPopup,
|
||||
final PsiElement context, @Nullable final String predefinedText) {
|
||||
super(project, model, oldPopup != null ? oldPopup.getEnteredText() : predefinedText, context);
|
||||
if (oldPopup == null && predefinedText != null) {
|
||||
setPreselectInitialText(true);
|
||||
}
|
||||
if (oldPopup != null) { //inherit old focus owner
|
||||
myOldFocusOwner = oldPopup.myPreviouslyFocusedComponent;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel {
|
||||
};
|
||||
}
|
||||
|
||||
protected String getActionId(AnAction anAction) {
|
||||
protected String getActionId(final @NotNull AnAction anAction) {
|
||||
return myActionManager.getId(anAction);
|
||||
}
|
||||
|
||||
@@ -219,13 +219,15 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel {
|
||||
private void collectActions(String id, Map<AnAction, String> result, ActionGroup group, final String containingGroupName){
|
||||
final AnAction[] actions = group.getChildren(null);
|
||||
for (AnAction action : actions) {
|
||||
if (action instanceof ActionGroup) {
|
||||
final ActionGroup actionGroup = (ActionGroup)action;
|
||||
final String groupName = actionGroup.getTemplatePresentation().getText();
|
||||
collectActions(id, result, actionGroup, groupName != null ? groupName : containingGroupName);
|
||||
} else if (getActionId(action) == id) {
|
||||
final String groupName = group.getTemplatePresentation().getText();
|
||||
result.put(action, groupName != null && groupName.length() > 0 ? groupName : containingGroupName);
|
||||
if (action != null) {
|
||||
if (action instanceof ActionGroup) {
|
||||
final ActionGroup actionGroup = (ActionGroup)action;
|
||||
final String groupName = actionGroup.getTemplatePresentation().getText();
|
||||
collectActions(id, result, actionGroup, groupName != null ? groupName : containingGroupName);
|
||||
} else if (getActionId(action) == id) {
|
||||
final String groupName = group.getTemplatePresentation().getText();
|
||||
result.put(action, groupName != null && groupName.length() > 0 ? groupName : containingGroupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-2
@@ -27,6 +27,7 @@ import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.SdkAdditionalData;
|
||||
import com.intellij.openapi.projectRoots.SdkType;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
@@ -104,11 +105,30 @@ public class SdkConfigurationUtil {
|
||||
|
||||
@Nullable
|
||||
public static Sdk setupSdk(final VirtualFile homeDir, final SdkType sdkType, final boolean silent) {
|
||||
return setupSdk(homeDir, sdkType, silent, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Sdk setupSdk(final VirtualFile homeDir, final SdkType sdkType, final boolean silent,
|
||||
@Nullable final SdkAdditionalData additionalData,
|
||||
@Nullable final String customSdkSuggestedName) {
|
||||
final Sdk[] sdks = ProjectJdkTable.getInstance().getAllJdks();
|
||||
final List<Sdk> sdksList = Arrays.asList(sdks);
|
||||
|
||||
final ProjectJdkImpl projectJdk;
|
||||
try {
|
||||
final String sdkName = createUniqueSdkName(sdkType, homeDir.getPath(), Arrays.asList(sdks));
|
||||
final String sdkName = customSdkSuggestedName == null
|
||||
? createUniqueSdkName(sdkType, homeDir.getPath(), sdksList)
|
||||
: createUniqueSdkName(customSdkSuggestedName, sdksList);
|
||||
projectJdk = new ProjectJdkImpl(sdkName, sdkType);
|
||||
|
||||
if (additionalData != null) {
|
||||
// additional initialization.
|
||||
// E.g. some ruby sdks must be initialized before
|
||||
// setupSdkPaths() method invocation
|
||||
projectJdk.setSdkAdditionalData(additionalData);
|
||||
}
|
||||
|
||||
projectJdk.setHomePath(homeDir.getPath());
|
||||
sdkType.setupSdkPaths(projectJdk);
|
||||
}
|
||||
@@ -195,11 +215,14 @@ public class SdkConfigurationUtil {
|
||||
}
|
||||
|
||||
public static String createUniqueSdkName(SdkType type, String home, final Collection<Sdk> sdks) {
|
||||
return createUniqueSdkName(type.suggestSdkName(null, home), sdks);
|
||||
}
|
||||
|
||||
public static String createUniqueSdkName(final String suggestedName, final Collection<Sdk> sdks) {
|
||||
final Set<String> names = new HashSet<String>();
|
||||
for (Sdk jdk : sdks) {
|
||||
names.add(jdk.getName());
|
||||
}
|
||||
final String suggestedName = type.suggestSdkName(null, home);
|
||||
String newSdkName = suggestedName;
|
||||
int i = 0;
|
||||
while (names.contains(newSdkName)) {
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public abstract class LightElement extends PsiElementBase {
|
||||
protected final PsiManager myManager;
|
||||
private final Language myLanguage;
|
||||
protected volatile PsiElement myNavigationElement = this;
|
||||
private volatile PsiElement myNavigationElement = this;
|
||||
|
||||
protected LightElement(PsiManager manager, final Language language) {
|
||||
myManager = manager;
|
||||
@@ -97,8 +97,9 @@ public abstract class LightElement extends PsiElementBase {
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if (myNavigationElement != this) {
|
||||
return myNavigationElement.isValid();
|
||||
final PsiElement navElement = getNavigationElement();
|
||||
if (navElement != this) {
|
||||
return navElement.isValid();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.intellij.unscramble;
|
||||
import com.intellij.execution.ExecutionManager;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.executors.DefaultRunExecutor;
|
||||
import com.intellij.execution.filters.Filter;
|
||||
import com.intellij.execution.filters.TextConsoleBuilder;
|
||||
import com.intellij.execution.filters.TextConsoleBuilderFactory;
|
||||
import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
@@ -33,6 +35,8 @@ import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.EditorSettings;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -48,6 +52,8 @@ import java.awt.datatransfer.Transferable;
|
||||
* @author yole
|
||||
*/
|
||||
public class AnalyzeStacktraceUtil {
|
||||
public static ExtensionPointName<Filter> EP_NAME = ExtensionPointName.create("com.intellij.analyzeStacktraceFilter");
|
||||
|
||||
private AnalyzeStacktraceUtil() {
|
||||
}
|
||||
|
||||
@@ -82,7 +88,12 @@ public class AnalyzeStacktraceUtil {
|
||||
}
|
||||
|
||||
public static ConsoleView addConsole(Project project, @Nullable ConsoleFactory consoleFactory, final String tabTitle) {
|
||||
final ConsoleView consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
|
||||
final TextConsoleBuilder builder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
|
||||
for(Filter filter: Extensions.getExtensions(EP_NAME, project)) {
|
||||
builder.addFilter(filter);
|
||||
}
|
||||
|
||||
final ConsoleView consoleView = builder.getConsole();
|
||||
final DefaultActionGroup toolbarActions = new DefaultActionGroup();
|
||||
JComponent consoleComponent = consoleFactory != null
|
||||
? consoleFactory.createConsoleComponent(consoleView, toolbarActions)
|
||||
|
||||
@@ -320,6 +320,7 @@ public class PluginManager {
|
||||
|
||||
if (!shouldLoadPlugins()) return true;
|
||||
}
|
||||
final List<String> pluginIds = pluginId == null ? null : StringUtil.split(pluginId, ",");
|
||||
|
||||
final boolean checkModuleDependencies = !ourAvailableModules.isEmpty() && !ourAvailableModules.contains("com.intellij.modules.all");
|
||||
if (checkModuleDependencies && !hasModuleDependencies(descriptor)) {
|
||||
@@ -333,8 +334,8 @@ public class PluginManager {
|
||||
shouldLoad = loadPluginCategory.equals(descriptor.getCategory());
|
||||
}
|
||||
else {
|
||||
if (pluginId != null) {
|
||||
shouldLoad = pluginId.equals(idString);
|
||||
if (pluginIds != null) {
|
||||
shouldLoad = pluginIds.contains(idString);
|
||||
if (!shouldLoad) {
|
||||
Map<PluginId,IdeaPluginDescriptor> map = new HashMap<PluginId, IdeaPluginDescriptor>();
|
||||
for (final IdeaPluginDescriptor pluginDescriptor : loaded) {
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ public abstract class FileTextFieldImpl implements FileLookup, Disposable, FileT
|
||||
for (KeyStroke eachListStroke : listKeys) {
|
||||
final String listActionID = (String)listMap.get(eachListStroke);
|
||||
if ("selectNextRow".equals(listActionID) || "selectPreviousRow".equals(listActionID)) {
|
||||
final String textActionID = (String)field.getInputMap().get(eachListStroke);
|
||||
final Object textActionID = field.getInputMap().get(eachListStroke);
|
||||
if (textActionID != null) {
|
||||
final Action textAction = field.getActionMap().get(textActionID);
|
||||
if (textAction != null) {
|
||||
|
||||
+1
@@ -86,6 +86,7 @@ public class InlineProgressIndicator extends ProgressIndicatorBase implements Di
|
||||
textAndProgress.add(myText, BorderLayout.CENTER);
|
||||
|
||||
final NonOpaquePanel progressWrapper = new NonOpaquePanel(new GridBagLayout());
|
||||
progressWrapper.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
|
||||
final GridBagConstraints c = new GridBagConstraints();
|
||||
c.weightx = 1;
|
||||
c.weighty = 1;
|
||||
|
||||
@@ -58,7 +58,7 @@ public class TextPanel extends JComponent {
|
||||
|
||||
@Override
|
||||
protected void paintComponent(final Graphics g) {
|
||||
final String s = getText();
|
||||
String s = getText();
|
||||
if (s != null) {
|
||||
final Rectangle bounds = getBounds();
|
||||
final Insets insets = getInsets();
|
||||
@@ -68,12 +68,28 @@ public class TextPanel extends JComponent {
|
||||
|
||||
UIUtil.applyRenderingHints(g2);
|
||||
|
||||
final FontMetrics fm = g2.getFontMetrics();
|
||||
final int sWidth = fm.stringWidth(s);
|
||||
|
||||
int x = insets.left;
|
||||
if (myAlignment == JComponent.CENTER_ALIGNMENT || myAlignment == JComponent.RIGHT_ALIGNMENT) {
|
||||
final int sWidth = g2.getFontMetrics().stringWidth(s);
|
||||
x = myAlignment == JComponent.CENTER_ALIGNMENT ? (bounds.width - sWidth) / 2 : bounds.width - insets.right - sWidth;
|
||||
}
|
||||
|
||||
final Rectangle textR = new Rectangle();
|
||||
final Rectangle iconR = new Rectangle();
|
||||
final Rectangle viewR = new Rectangle(bounds);
|
||||
textR.x = textR.y = textR.width = textR.height = 0;
|
||||
|
||||
viewR.width -= insets.left;
|
||||
viewR.width -= insets.right;
|
||||
|
||||
if (sWidth > (bounds.width - insets.left - insets.right)) {
|
||||
s = SwingUtilities
|
||||
.layoutCompoundLabel(fm, s, null, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.TRAILING,
|
||||
bounds, iconR, textR, 0);
|
||||
}
|
||||
|
||||
final int y = UIUtil.getStringY(s, bounds, g2);
|
||||
if (SystemInfo.isMac && myDecorate) {
|
||||
g2.setColor(new Color(215, 215, 215));
|
||||
|
||||
@@ -436,4 +436,6 @@
|
||||
<extensionPoint name="typeName" beanClass="com.intellij.ide.TypeNameEP"/>
|
||||
|
||||
<extensionPoint name="typeIcon" beanClass="com.intellij.ide.TypeIconEP"/>
|
||||
|
||||
<extensionPoint name="analyzeStacktraceFilter" interface="com.intellij.execution.filters.Filter" area="IDEA_PROJECT"/>
|
||||
</extensionPoints>
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
<group id="AddAllToFavorites" class="com.intellij.ide.favoritesTreeView.actions.AddAllToFavoritesActionGroup" popup="true"/>
|
||||
<action id="AddNewFavoritesList" class="com.intellij.ide.favoritesTreeView.actions.AddNewFavoritesListAction"/>
|
||||
<group id="SendToFavoritesGroup" class="com.intellij.ide.favoritesTreeView.actions.SendToFavoritesGroup" popup="true"/>
|
||||
<group id="MoveModuleToGroup" class="com.intellij.ide.projectView.impl.MoveModuleToGroupTopLevel" popup="true"/>
|
||||
|
||||
|
||||
<action id="RunConfiguration" class="com.intellij.execution.actions.RunConfigurationAction"/>
|
||||
<action id="ChooseRunConfiguration" class="com.intellij.execution.actions.ChooseRunConfigurationAction" text="Run..." icon="/general/toolWindowRun.png"/>
|
||||
<action id="ChooseDebugConfiguration" class="com.intellij.execution.actions.ChooseDebugConfigurationAction" text="Debug..." icon="/general/debug.png"/>
|
||||
@@ -392,7 +391,6 @@
|
||||
</group>
|
||||
|
||||
<group id="ProjectViewPopupMenuSettingsGroup">
|
||||
<reference ref="MoveModuleToGroup"/>
|
||||
</group>
|
||||
|
||||
<group id="ProjectViewPopupMenu">
|
||||
|
||||
@@ -53,7 +53,7 @@ public abstract class ParsingTestCase extends LightPlatformTestCase {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void doTest(boolean checkResult) throws Exception{
|
||||
protected void doTest(boolean checkResult) throws Exception {
|
||||
String name = getTestName(false);
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
@@ -67,7 +67,7 @@ public abstract class ParsingTestCase extends LightPlatformTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
protected void doTest(String suffix) throws Exception{
|
||||
protected void doTest(String suffix) throws IOException {
|
||||
String name = getTestName(false);
|
||||
String text = loadFile(name + "." + myFileExt);
|
||||
myFile = createPsiFile(name, text);
|
||||
@@ -80,11 +80,11 @@ public abstract class ParsingTestCase extends LightPlatformTestCase {
|
||||
return createFile(name + "." + myFileExt, text);
|
||||
}
|
||||
|
||||
protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws Exception {
|
||||
protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
|
||||
doCheckResult(myFullDataPath, file, targetDataName, includeRanges());
|
||||
}
|
||||
|
||||
public static void doCheckResult(String myFullDataPath, PsiFile file, String targetDataName, boolean printRanges) throws Exception {
|
||||
public static void doCheckResult(String myFullDataPath, PsiFile file, String targetDataName, boolean printRanges) throws IOException {
|
||||
final PsiElement[] psiRoots = file.getPsiRoots();
|
||||
if(psiRoots.length > 1){
|
||||
for (int i = 0; i < psiRoots.length; i++) {
|
||||
@@ -97,11 +97,11 @@ public abstract class ParsingTestCase extends LightPlatformTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkResult(@TestDataFile @NonNls String targetDataName, final String text) throws Exception {
|
||||
protected void checkResult(@TestDataFile @NonNls String targetDataName, final String text) throws IOException {
|
||||
doCheckResult(myFullDataPath, targetDataName, text);
|
||||
}
|
||||
|
||||
private static void doCheckResult(String myFullDataPath, String targetDataName, String text) throws Exception {
|
||||
private static void doCheckResult(String myFullDataPath, String targetDataName, String text) throws IOException {
|
||||
try {
|
||||
text = text.trim();
|
||||
String expectedText = doLoadFile(myFullDataPath, targetDataName);
|
||||
@@ -124,7 +124,7 @@ public abstract class ParsingTestCase extends LightPlatformTestCase {
|
||||
return DebugUtil.psiToString(file, false, printRanges);
|
||||
}
|
||||
|
||||
protected String loadFile(@NonNls @TestDataFile String name) throws Exception {
|
||||
protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
|
||||
return doLoadFile(myFullDataPath, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,13 @@ import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
//TeamCity inherits StringUtil: do not add private constructors!!!
|
||||
public class StringUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.text.StringUtil");
|
||||
@NonNls private static final String VOWELS = "aeiouy";
|
||||
private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *");
|
||||
|
||||
public static String replace(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @Nullable String newS) {
|
||||
return replace(text, oldS, newS, false);
|
||||
@@ -1600,4 +1602,14 @@ public class StringUtil {
|
||||
public static String tail(@NotNull String s, final int idx) {
|
||||
return idx >= s.length() ? "" : s.substring(idx, s.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits string by lines.
|
||||
*
|
||||
* @param string String to split
|
||||
* @return array of strings
|
||||
*/
|
||||
public static String[] splitByLines(final String string) {
|
||||
return EOL_SPLIT_PATTERN.split(string);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
<orderEntry type="module" module-name="properties" />
|
||||
<orderEntry type="module" module-name="execution-openapi" />
|
||||
<orderEntry type="module" module-name="idea-ui" />
|
||||
<orderEntry type="module" module-name="dom-openapi" />
|
||||
<orderEntry type="module" module-name="dom-openapi" exported="" />
|
||||
<orderEntry type="module" module-name="xml-openapi" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="idea-tests" scope="TEST" />
|
||||
|
||||
@@ -53,13 +53,13 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
}
|
||||
else {
|
||||
final Map<String, Class> tasks = reflected.getTaskDefinitions();
|
||||
final Class taskClass = (Class)tasks.get(tagName);
|
||||
final Class taskClass = tasks.get(tagName);
|
||||
if (taskClass != null) {
|
||||
parentElementIntrospector = getIntrospector(taskClass);
|
||||
}
|
||||
else {
|
||||
final Map<String, Class> dataTypes = reflected.getDataTypeDefinitions();
|
||||
final Class dataClass = (Class)dataTypes.get(tagName);
|
||||
final Class dataClass = dataTypes.get(tagName);
|
||||
if (dataClass != null) {
|
||||
parentElementIntrospector = getIntrospector(dataClass);
|
||||
}
|
||||
@@ -83,9 +83,9 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Enumeration nested = parentElementIntrospector.getNestedElements();
|
||||
final Enumeration<String> nested = parentElementIntrospector.getNestedElements();
|
||||
while (nested.hasMoreElements()) {
|
||||
registerChild(registrar, genericInfo, (String)nested.nextElement());
|
||||
registerChild(registrar, genericInfo, nested.nextElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class AntDomExtender extends DomExtender<AntDomElement>{
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AntIntrospector getIntrospector(Class c) {
|
||||
public static AntIntrospector getIntrospector(Class c) {
|
||||
try {
|
||||
return AntIntrospector.getInstance(c);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public final class AntIntrospector {
|
||||
return types;
|
||||
}
|
||||
|
||||
public Enumeration getNestedElements() {
|
||||
public Enumeration<String> getNestedElements() {
|
||||
return invokeMethod("getNestedElements", false);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.testFramework.ParsingTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CustomTypesTest extends ParsingTestCase {
|
||||
|
||||
@@ -63,7 +64,7 @@ public class CustomTypesTest extends ParsingTestCase {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String loadFile(String name) throws Exception {
|
||||
protected String loadFile(String name) throws IOException {
|
||||
String fullName = getTestDataPath() + File.separatorChar + name;
|
||||
String text = new String(FileUtil.loadFileText(new File(fullName))).trim();
|
||||
text = StringUtil.convertLineSeparators(text);
|
||||
|
||||
@@ -27,9 +27,9 @@ import java.io.File;
|
||||
* The application wide settings for the git
|
||||
*/
|
||||
@State(
|
||||
name = "PasswordSafe",
|
||||
name = "Git.Application.Settings",
|
||||
storages = {@Storage(
|
||||
id = "PasswordSafe",
|
||||
id = "Git.Application.Settings",
|
||||
file = "$APP_CONFIG$/vcs.xml")})
|
||||
public class GitVcsApplicationSettings implements PersistentStateComponent<GitVcsApplicationSettings.State> {
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,8 @@ import org.codehaus.groovy.tools.javac.JavaAwareResolveVisitor;
|
||||
import org.codehaus.groovy.tools.javac.JavaStubGenerator;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
@@ -341,10 +343,16 @@ public class GroovycRunner {
|
||||
final Enumeration resources = super.getResources(name);
|
||||
final ArrayList list = Collections.list(resources);
|
||||
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
|
||||
String file = ((URL)iterator.next()).getFile();
|
||||
System.out.println("Enumerated:" + file);
|
||||
if (file.startsWith(finalOutput) || file.startsWith("/" + finalOutput)) {
|
||||
iterator.remove();
|
||||
final URL url = (URL)iterator.next();
|
||||
try {
|
||||
final String file = new File(new URI(url.toString())).getCanonicalPath();
|
||||
System.out.println("Enumerated:" + file);
|
||||
if (file.startsWith(finalOutput) || file.startsWith("/" + finalOutput)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
System.out.println("Invalid URI syntax: " + url.toString());
|
||||
}
|
||||
}
|
||||
return Collections.enumeration(list);
|
||||
|
||||
@@ -71,7 +71,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.util.GroovyUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
@@ -304,9 +303,7 @@ public abstract class GroovyCompilerBase implements TranslatingCompiler {
|
||||
printer.println(PathUtil.getLocalPath(outputDir));
|
||||
|
||||
printer.println(GroovycRunner.FINAL_OUTPUTPATH);
|
||||
final URL finalUrl = VfsUtil.convertToURL(finalOutputDir.getUrl());
|
||||
LOG.assertTrue(finalUrl != null, finalOutputDir.getPath());
|
||||
printer.println(finalUrl.getFile());
|
||||
printer.println(FileUtil.toSystemDependentName(finalOutputDir.getPath()));
|
||||
|
||||
|
||||
printer.close();
|
||||
|
||||
@@ -77,7 +77,7 @@ public class CustomMembersGenerator implements GdslMembersHolderConsumer {
|
||||
public CustomMembersHolder getMembersHolder() {
|
||||
// Add non-code members holder
|
||||
if (myClassText.length() > 0) {
|
||||
addMemberHolder(NonCodeMembersHolder.fromText(myClassText.toString(), myProject));
|
||||
addMemberHolder(NonCodeMembersHolder.fromText(myClassText.toString(), myPlace.containingFile));
|
||||
}
|
||||
return myDepot;
|
||||
}
|
||||
|
||||
+6
-5
@@ -24,9 +24,9 @@ import org.jetbrains.plugins.groovy.dsl.GdslMembersHolderConsumer;
|
||||
import org.jetbrains.plugins.groovy.dsl.holders.DelegatedMembersHolder;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
|
||||
|
||||
@@ -147,10 +147,11 @@ public class GroovyDslDefaultMembers implements GdslMembersProvider {
|
||||
|
||||
@Nullable
|
||||
private static String getInvokedMethodName(GrCall call) {
|
||||
final GrExpression expr = call instanceof GrApplicationStatement ? ((GrApplicationStatement)call).getFunExpression() :
|
||||
call instanceof GrMethodCallExpression ? ((GrMethodCallExpression)call).getInvokedExpression() : null;
|
||||
if (expr instanceof GrReferenceExpression) {
|
||||
return ((GrReferenceExpression)expr).getName();
|
||||
if (call instanceof GrMethodCall) {
|
||||
final GrExpression expr = ((GrMethodCall)call).getInvokedExpression();
|
||||
if (expr instanceof GrReferenceExpression) {
|
||||
return ((GrReferenceExpression)expr).getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+7
-10
@@ -15,11 +15,8 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.dsl.holders;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.NameHint;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
@@ -38,13 +35,13 @@ public class NonCodeMembersHolder implements CustomMembersHolder {
|
||||
private final GrTypeDefinition myPsiClass;
|
||||
private static final Key<CachedValue<ConcurrentFactoryMap<String, NonCodeMembersHolder>>> CACHED_HOLDERS = Key.create("CACHED_HOLDERS");
|
||||
|
||||
public static NonCodeMembersHolder fromText(@NotNull String classText, final Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, CACHED_HOLDERS, new CachedValueProvider<ConcurrentFactoryMap<String, NonCodeMembersHolder>>() {
|
||||
public static NonCodeMembersHolder fromText(@NotNull String classText, final PsiFile place) {
|
||||
return CachedValuesManager.getManager(place.getProject()).getCachedValue(place, CACHED_HOLDERS, new CachedValueProvider<ConcurrentFactoryMap<String, NonCodeMembersHolder>>() {
|
||||
public Result<ConcurrentFactoryMap<String, NonCodeMembersHolder>> compute() {
|
||||
final ConcurrentFactoryMap<String, NonCodeMembersHolder> map = new ConcurrentFactoryMap<String, NonCodeMembersHolder>() {
|
||||
@Override
|
||||
protected NonCodeMembersHolder create(String key) {
|
||||
return new NonCodeMembersHolder(key, project);
|
||||
return new NonCodeMembersHolder(key, place);
|
||||
}
|
||||
};
|
||||
return Result.create(map, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
@@ -52,9 +49,9 @@ public class NonCodeMembersHolder implements CustomMembersHolder {
|
||||
}, false).get(classText);
|
||||
}
|
||||
|
||||
private NonCodeMembersHolder(@NotNull String classText, Project project) {
|
||||
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
|
||||
myPsiClass = factory.createGroovyFile("class GroovyEnhanced {\n" + classText + "}", false, null).getTypeDefinitions()[0];
|
||||
private NonCodeMembersHolder(@NotNull String classText, PsiElement place) {
|
||||
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(place.getProject());
|
||||
myPsiClass = factory.createGroovyFile("class GroovyEnhanced {\n" + classText + "}", false, place).getTypeDefinitions()[0];
|
||||
}
|
||||
|
||||
public boolean processMembers(PsiScopeProcessor processor) {
|
||||
|
||||
@@ -22,10 +22,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -39,9 +38,7 @@ public class PsiElementCategory implements PsiEnhancerCategory {
|
||||
|
||||
@Nullable
|
||||
public static PsiElement bind(PsiElement element) {
|
||||
PsiElement elem = element instanceof GrMethodCallExpression ? ((GrMethodCallExpression)element).getInvokedExpression() :
|
||||
element instanceof GrApplicationStatement ? ((GrApplicationStatement)element).getFunExpression() :
|
||||
element;
|
||||
PsiElement elem = element instanceof GrMethodCall ? ((GrMethodCall)element).getInvokedExpression() : element;
|
||||
final PsiReference ref = elem.getReference();
|
||||
return ref == null ? null : ref.resolve();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.jetbrains.plugins.groovy.gant;
|
||||
|
||||
import com.intellij.lang.ant.dom.AntDomExtender;
|
||||
import com.intellij.lang.ant.psi.impl.AntIntrospector;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class AntBuilderMethod extends LightMethodBuilder {
|
||||
private final PsiFile myPlace;
|
||||
@Nullable private final Class myAntClass;
|
||||
|
||||
public AntBuilderMethod(PsiFile place, String name, PsiType closureType, @Nullable Class antClass) {
|
||||
super(place.getManager(), GroovyFileType.GROOVY_LANGUAGE, name);
|
||||
myPlace = place;
|
||||
myAntClass = antClass;
|
||||
setModifiers(PsiModifier.PUBLIC);
|
||||
addParameter("args", CommonClassNames.JAVA_UTIL_MAP);
|
||||
setBaseIcon(GantIcons.ANT_TASK);
|
||||
addParameter(new GrLightParameter("body", closureType, this).setOptional(true));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
if (myAntClass != null) {
|
||||
final PsiClass psiClass = JavaPsiFacade.getInstance(getProject()).findClass(myAntClass.getName(), myPlace.getResolveScope());
|
||||
if (psiClass != null) {
|
||||
return psiClass;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean processNestedElements(PsiScopeProcessor processor) {
|
||||
final AntIntrospector introspector = AntDomExtender.getIntrospector(myAntClass);
|
||||
if (introspector != null) {
|
||||
final Enumeration<String> nested = introspector.getNestedElements();
|
||||
while (nested.hasMoreElements()) {
|
||||
final AntBuilderMethod method =
|
||||
new AntBuilderMethod(myPlace, nested.nextElement(), getParameterList().getParameters()[1].getType(), null);
|
||||
if (!ResolveUtil.processElement(processor, method)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -27,18 +27,15 @@ import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
import org.jetbrains.plugins.groovy.extensions.GroovyScriptType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
@@ -79,29 +76,12 @@ public class AntTasksProvider {
|
||||
final Set<LightMethodBuilder> result = new HashSet<LightMethodBuilder>();
|
||||
|
||||
final Project project = file.getProject();
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
||||
final GlobalSearchScope scope = file.getResolveScope();
|
||||
|
||||
final PsiType closureType = JavaPsiFacade.getElementFactory(project).createTypeFromText(GrClosableBlock.GROOVY_LANG_CLOSURE,
|
||||
file);
|
||||
final PsiType closureType = JavaPsiFacade.getElementFactory(project).createTypeFromText(GrClosableBlock.GROOVY_LANG_CLOSURE, file);
|
||||
|
||||
for (String name : antObjects.keySet()) {
|
||||
final PsiClass psiClass = facade.findClass(antObjects.get(name).getName(), scope);
|
||||
|
||||
final LightMethodBuilder tdMethod =
|
||||
new LightMethodBuilder(PsiManager.getInstance(project), GroovyFileType.GROOVY_LANGUAGE, name).
|
||||
setModifiers(PsiModifier.PUBLIC).
|
||||
addParameter("args", CommonClassNames.JAVA_UTIL_MAP).
|
||||
setBaseIcon(GantIcons.ANT_TASK);
|
||||
|
||||
tdMethod.addParameter(new GrLightParameter("body", closureType, tdMethod).setOptional(true));
|
||||
|
||||
if (psiClass != null) {
|
||||
tdMethod.setNavigationElement(psiClass);
|
||||
}
|
||||
result.add(tdMethod);
|
||||
result.add(new AntBuilderMethod(file, name, closureType, antObjects.get(name)));
|
||||
}
|
||||
return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(file.getProject()));
|
||||
return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.gant;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder;
|
||||
import com.intellij.psi.impl.light.LightVariableBuilder;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
@@ -26,6 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
|
||||
@@ -45,13 +43,35 @@ public class GantMemberContributor implements NonCodeMembersProcessor {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiFile file = place.getContainingFile();
|
||||
if (!GantUtils.isGantScriptFile(file)) {
|
||||
GrClosableBlock closure = PsiTreeUtil.getContextOfType(place, GrClosableBlock.class, true);
|
||||
if (closure == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final GrClosableBlock closure = PsiTreeUtil.getContextOfType(place, GrClosableBlock.class, true);
|
||||
if (closure == null) {
|
||||
boolean antTasksProcessed = false;
|
||||
while (closure != null) {
|
||||
final PsiElement parent = closure.getParent();
|
||||
if (parent instanceof GrMethodCall) {
|
||||
final PsiMethod method = ((GrMethodCall)parent).resolveMethod();
|
||||
if (method instanceof AntBuilderMethod) {
|
||||
antTasksProcessed = true;
|
||||
if (!processAntTasks(processor, place)) {
|
||||
return false;
|
||||
}
|
||||
if (!((AntBuilderMethod)method).processNestedElements(processor)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closure = PsiTreeUtil.getContextOfType(closure, GrClosableBlock.class, true);
|
||||
}
|
||||
|
||||
// ------- gant-specific
|
||||
|
||||
PsiFile file = place.getContainingFile();
|
||||
if (!GantUtils.isGantScriptFile(file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,7 +86,7 @@ public class GantMemberContributor implements NonCodeMembersProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
return processAntTasks(processor, place);
|
||||
return antTasksProcessed || processAntTasks(processor, place);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -17,17 +17,16 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
|
||||
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
*/
|
||||
public interface GrApplicationStatement extends GrStatement, GrCall {
|
||||
public interface GrApplicationStatement extends GrStatement, GrMethodCall {
|
||||
/**
|
||||
* @deprecated use {@link GrMethodCall#getInvokedExpression()}
|
||||
*/
|
||||
GrExpression getFunExpression();
|
||||
|
||||
GrExpression[] getArguments();
|
||||
|
||||
GrArgumentList getArgumentList();
|
||||
|
||||
//PsiElement addNamedArgument(GrNamedArgument argument);
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
|
||||
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public interface GrMethodCall extends GrCall {
|
||||
|
||||
GrExpression getInvokedExpression();
|
||||
|
||||
@Nullable
|
||||
GrArgumentList getArgumentList();
|
||||
|
||||
@Nullable
|
||||
PsiMethod resolveMethod();
|
||||
}
|
||||
+2
-3
@@ -20,13 +20,12 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
*/
|
||||
public interface GrMethodCallExpression extends GrCallExpression {
|
||||
|
||||
GrExpression getInvokedExpression();
|
||||
public interface GrMethodCallExpression extends GrCallExpression, GrMethodCall {
|
||||
|
||||
GrExpression replaceClosureArgument(@NotNull GrClosableBlock closure, @NotNull GrExpression newExpr) throws IncorrectOperationException;
|
||||
|
||||
|
||||
@@ -468,6 +468,11 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
|
||||
}
|
||||
};
|
||||
public GlobalSearchScope getFileResolveScope() {
|
||||
final PsiElement context = getContext();
|
||||
if (context instanceof GroovyFile) {
|
||||
return context.getResolveScope();
|
||||
}
|
||||
|
||||
final VirtualFile vFile = getOriginalFile().getVirtualFile();
|
||||
if (vFile == null) {
|
||||
return GlobalSearchScope.allScope(getProject());
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.bitwise.GrAndExpressionImpl;
|
||||
@@ -137,18 +136,17 @@ public class PsiImplUtil {
|
||||
if (qualifier == null) {
|
||||
GrClosableBlock closure = PsiTreeUtil.getParentOfType(refExpr, GrClosableBlock.class);
|
||||
while (closure != null) {
|
||||
GrExpression funExpr = null;
|
||||
PsiElement parent = closure.getParent();
|
||||
if (parent instanceof GrApplicationStatement) {
|
||||
funExpr = ((GrApplicationStatement) parent).getFunExpression();
|
||||
} else if (parent instanceof GrMethodCallExpression) {
|
||||
funExpr = ((GrMethodCallExpression) parent).getInvokedExpression();
|
||||
if (parent instanceof GrMethodCall) {
|
||||
GrExpression funExpr = ((GrMethodCall)parent).getInvokedExpression();
|
||||
if (funExpr instanceof GrReferenceExpression) {
|
||||
qualifier = ((GrReferenceExpression) funExpr).getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
return qualifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (funExpr instanceof GrReferenceExpression) {
|
||||
qualifier = ((GrReferenceExpression) funExpr).getQualifierExpression();
|
||||
if (qualifier != null) break;
|
||||
}
|
||||
|
||||
closure = PsiTreeUtil.getParentOfType(closure, GrClosableBlock.class);
|
||||
}
|
||||
@@ -354,4 +352,14 @@ public class PsiImplUtil {
|
||||
return method.getName().equals(MAIN_METHOD) &&
|
||||
method.hasModifierProperty(PsiModifier.STATIC);
|
||||
}
|
||||
|
||||
public static PsiMethod resolveMethod(GrMethodCall expression) {
|
||||
final GrExpression methodExpr = expression.getInvokedExpression();
|
||||
if (methodExpr instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression) methodExpr).resolve();
|
||||
return resolved instanceof PsiMethod ? (PsiMethod) resolved : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplic
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
@@ -45,7 +47,7 @@ public class GrApplicationStatementImpl extends GrExpressionImpl implements GrAp
|
||||
}
|
||||
|
||||
public GrExpression getFunExpression() {
|
||||
return findChildByClass(GrExpression.class);
|
||||
return getInvokedExpression();
|
||||
}
|
||||
|
||||
public GrExpression[] getArguments() {
|
||||
@@ -54,6 +56,15 @@ public class GrApplicationStatementImpl extends GrExpressionImpl implements GrAp
|
||||
return list.getExpressionArguments();
|
||||
}
|
||||
|
||||
public PsiMethod resolveMethod() {
|
||||
return PsiImplUtil.resolveMethod(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrExpression getInvokedExpression() {
|
||||
return findNotNullChildByClass(GrExpression.class);
|
||||
}
|
||||
|
||||
public GrCommandArgumentList getArgumentList() {
|
||||
return findChildByClass(GrCommandArgumentList.class);
|
||||
}
|
||||
|
||||
+2
-7
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceExpressionImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
@@ -181,13 +182,7 @@ public class GrMethodCallExpressionImpl extends GrCallExpressionImpl implements
|
||||
}
|
||||
|
||||
public PsiMethod resolveMethod() {
|
||||
final GrExpression methodExpr = getInvokedExpression();
|
||||
if (methodExpr instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression) methodExpr).resolve();
|
||||
return resolved instanceof PsiMethod ? (PsiMethod) resolved : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return PsiImplUtil.resolveMethod(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+20
-18
@@ -19,7 +19,6 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
@@ -54,18 +53,6 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
this(parameters, returnType, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(@NotNull GrClosableBlock block) {
|
||||
this(block.getAllParameters(), block.getReturnType());
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(@NotNull PsiMethod method) {
|
||||
this(method, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(@NotNull PsiMethod method, @NotNull PsiSubstitutor substitutor) {
|
||||
this(method.getParameterList().getParameters(), PsiUtil.getSmartReturnType(method), substitutor);
|
||||
}
|
||||
|
||||
GrClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
|
||||
myParameters = params;
|
||||
myReturnType = returnType;
|
||||
@@ -99,7 +86,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
public GrClosureSignature curry(int count) {
|
||||
if (count > myParameters.length) {
|
||||
if (isVarargs()) {
|
||||
return new GrClosureSignatureImpl(GrClosureParameter.EMPTY_ARRAY, myReturnType);
|
||||
return new DerivedClosureSignature();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@@ -107,22 +94,22 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
}
|
||||
GrClosureParameter[] newParams = new GrClosureParameter[myParameters.length - count];
|
||||
System.arraycopy(myParameters, count, newParams, 0, newParams.length);
|
||||
return new GrClosureSignatureImpl(newParams, myReturnType, myIsVarargs);
|
||||
return new DerivedClosureSignature(newParams, null, myIsVarargs);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
for (GrClosureParameter parameter : myParameters) {
|
||||
if (!parameter.isValid()) return false;
|
||||
}
|
||||
return myReturnType == null || myReturnType.isValid();
|
||||
final PsiType returnType = getReturnType();
|
||||
return returnType == null || returnType.isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof GrClosureSignature) {
|
||||
return Comparing.equal(myParameters, ((GrClosureSignature)obj).getParameters()) &&
|
||||
Comparing.equal(myIsVarargs, ((GrClosureSignature)obj).isVarargs()) &&
|
||||
Comparing.equal(myReturnType, ((GrClosureSignature)obj).getReturnType());
|
||||
Comparing.equal(myIsVarargs, ((GrClosureSignature)obj).isVarargs());
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
@@ -152,5 +139,20 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
}
|
||||
return null; //todo
|
||||
}
|
||||
|
||||
private class DerivedClosureSignature extends GrClosureSignatureImpl {
|
||||
DerivedClosureSignature() {
|
||||
super(GrClosureParameter.EMPTY_ARRAY, null);
|
||||
}
|
||||
|
||||
DerivedClosureSignature(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
|
||||
super(params, returnType, isVarArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType getReturnType() {
|
||||
return GrClosureSignatureImpl.this.getReturnType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-4
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -48,12 +49,22 @@ public class GrClosureSignatureUtil {
|
||||
private GrClosureSignatureUtil() {
|
||||
}
|
||||
|
||||
public static GrClosureSignature createSignature(GrClosableBlock block) {
|
||||
return new GrClosureSignatureImpl(block);
|
||||
public static GrClosureSignature createSignature(final GrClosableBlock block) {
|
||||
return new GrClosureSignatureImpl(block.getAllParameters(), null) {
|
||||
@Override
|
||||
public PsiType getReturnType() {
|
||||
return block.getReturnType();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static GrClosureSignature createSignature(PsiMethod method, PsiSubstitutor substitutor) {
|
||||
return new GrClosureSignatureImpl(method, substitutor);
|
||||
public static GrClosureSignature createSignature(final PsiMethod method, PsiSubstitutor substitutor) {
|
||||
return new GrClosureSignatureImpl(method.getParameterList().getParameters(), null, substitutor) {
|
||||
@Override
|
||||
public PsiType getReturnType() {
|
||||
return PsiUtil.getSmartReturnType(method);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static GrClosureSignature createSignature(PsiParameter[] parameters, PsiType returnType) {
|
||||
|
||||
+3
-3
@@ -292,7 +292,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl implement
|
||||
}
|
||||
if (kind == CLASS) return;
|
||||
|
||||
PsiPackage[] subpackages = aPackage.getSubPackages();
|
||||
PsiPackage[] subpackages = aPackage.getSubPackages(getResolveScope());
|
||||
for (PsiPackage subpackage : subpackages) {
|
||||
consumer.consume(subpackage);
|
||||
}
|
||||
@@ -385,7 +385,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl implement
|
||||
}
|
||||
|
||||
if (kind == CLASS_OR_PACKAGE) {
|
||||
for (final PsiPackage subpackage : ((PsiPackage) qualifierResolved).getSubPackages()) {
|
||||
for (final PsiPackage subpackage : ((PsiPackage) qualifierResolved).getSubPackages(ref.getResolveScope())) {
|
||||
if (refName.equals(subpackage.getName()))
|
||||
return new GroovyResolveResult[]{new GroovyResolveResultImpl(subpackage, true)};
|
||||
}
|
||||
@@ -410,7 +410,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl implement
|
||||
if (kind == CLASS_OR_PACKAGE) {
|
||||
PsiPackage defaultPackage = JavaPsiFacade.getInstance(ref.getProject()).findPackage("");
|
||||
if (defaultPackage != null) {
|
||||
for (final PsiPackage subpackage : defaultPackage.getSubPackages()) {
|
||||
for (final PsiPackage subpackage : defaultPackage.getSubPackages(ref.getResolveScope())) {
|
||||
if (refName.equals(subpackage.getName()))
|
||||
return new GroovyResolveResult[]{new GroovyResolveResultImpl(subpackage, true)};
|
||||
}
|
||||
|
||||
+24
-1
@@ -106,6 +106,29 @@ def foo() {
|
||||
checkVariants "ant.patt<caret>t", "patternset"
|
||||
}
|
||||
|
||||
public void testTagsInsideTags() throws Exception {
|
||||
myFixture.configureByText "a.groovy", """
|
||||
AntBuilder ant
|
||||
ant.zip {
|
||||
patternset {
|
||||
includ<caret>
|
||||
}
|
||||
}"""
|
||||
myFixture.completeBasic()
|
||||
assertSameElements myFixture.lookupElementStrings, "include", "includesfile"
|
||||
}
|
||||
|
||||
public void testTagsInsideTagsInGantTarget() throws Exception {
|
||||
checkVariants """
|
||||
target(aaa: "") {
|
||||
zip {
|
||||
patternset {
|
||||
includ<caret>
|
||||
}
|
||||
}
|
||||
}""", "include", "includesfile", "includeTargets", "includeTool"
|
||||
}
|
||||
|
||||
static final def GANT_JARS = ["gant.jar", "ant.jar", "ant-junit.jar", "ant-launcher.jar", "commons.jar"]
|
||||
|
||||
}
|
||||
@@ -126,7 +149,7 @@ class GantProjectDescriptor implements LightProjectDescriptor {
|
||||
modifiableModel.addRoot(fs.findFileByPath("$TestUtils.mockGroovyLibraryHome/$TestUtils.GROOVY_JAR!/"), OrderRootType.CLASSES);
|
||||
|
||||
GantReferenceCompletionTest.GANT_JARS.each {
|
||||
modifiableModel.addRoot(fs.findFileByPath("${TestUtils.absoluteTestDataPath}mockGantLib/$it!/"), OrderRootType.CLASSES);
|
||||
modifiableModel.addRoot(fs.findFileByPath("${TestUtils.absoluteTestDataPath}mockGantLib/lib/$it!/"), OrderRootType.CLASSES);
|
||||
}
|
||||
modifiableModel.commit();
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.jetbrains.plugins.groovy.gant.completion;
|
||||
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.plugins.groovy.gant.GantSettings
|
||||
import org.jetbrains.plugins.groovy.util.SdkHomeConfigurable.SdkHomeBean
|
||||
import org.jetbrains.plugins.groovy.util.TestUtils
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class StandaloneGantCompletionTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return TestUtils.getTestDataPath() + "gant/completion";
|
||||
}
|
||||
|
||||
@Override protected void setUp() {
|
||||
super.setUp();
|
||||
final SdkHomeBean state = new SdkHomeBean();
|
||||
state.SDK_HOME = FileUtil.toSystemIndependentName("${TestUtils.absoluteTestDataPath}mockGantLib");
|
||||
GantSettings.getInstance(getProject()).loadState state
|
||||
}
|
||||
|
||||
@Override protected void tearDown() {
|
||||
GantSettings.getInstance(getProject()).loadState new SdkHomeBean()
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
void checkVariants(String text, String... items) {
|
||||
myFixture.configureByText "a.gant", text
|
||||
myFixture.completeBasic()
|
||||
assertSameElements myFixture.lookupElementStrings, items
|
||||
}
|
||||
|
||||
public void testDep() throws Throwable {
|
||||
checkVariants """
|
||||
target(aaa: "") {
|
||||
dep<caret>
|
||||
}
|
||||
""", "depends", "dependset"
|
||||
}
|
||||
|
||||
public void testPatternset() throws Exception {
|
||||
checkVariants "ant.patt<caret>t", "patternset"
|
||||
}
|
||||
|
||||
static final def GANT_JARS = ["gant.jar", "ant.jar", "ant-junit.jar", "ant-launcher.jar", "commons.jar"]
|
||||
|
||||
}
|
||||
|
||||
Vendored
Vendored
@@ -20,7 +20,11 @@ public class MethodCallInSuperTest extends JDialog {
|
||||
private JComponent myRootComponent;
|
||||
|
||||
public MethodCallInSuperTest() {
|
||||
super(JOptionPane.getRootFrame(), "", true);
|
||||
super(getNullFrame(), "", true);
|
||||
getContentPane().add(myRootComponent);
|
||||
}
|
||||
|
||||
private static JFrame getNullFrame() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -345,6 +345,7 @@
|
||||
</group>
|
||||
|
||||
<action id="ModuleSettings" class="com.intellij.ide.actions.ShowModulePropertiesAction"/>
|
||||
<group id="MoveModuleToGroup" class="com.intellij.ide.projectView.impl.MoveModuleToGroupTopLevel" popup="true"/>
|
||||
|
||||
<reference ref="AnalyzeMenu">
|
||||
<add-to-group group-id="ProjectViewPopupMenu" anchor="after" relative-to-action="ReplaceInPath"/>
|
||||
@@ -381,6 +382,10 @@
|
||||
</action>
|
||||
|
||||
|
||||
<reference ref="MoveModuleToGroup">
|
||||
<add-to-group group-id="ProjectViewPopupMenuSettingsGroup" anchor="first"/>
|
||||
</reference>
|
||||
|
||||
<reference ref="ModuleSettings">
|
||||
<add-to-group group-id="ProjectViewPopupMenuSettingsGroup" anchor="first"/>
|
||||
</reference>
|
||||
|
||||
@@ -28,4 +28,9 @@ public class FilterToken extends Token {
|
||||
public String getSuffix() {
|
||||
return mySuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "|" + mySuffix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,5 +18,9 @@ package com.intellij.codeInsight.template.zencoding;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class MarkerToken extends Token {
|
||||
public class MarkerToken extends Token {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "&";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.intellij.codeInsight.template.zencoding;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class NumberToken extends Token {
|
||||
public class NumberToken extends Token {
|
||||
private final int myNumber;
|
||||
|
||||
NumberToken(int number) {
|
||||
@@ -28,4 +28,9 @@ class NumberToken extends Token {
|
||||
public int getNumber() {
|
||||
return myNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toString(myNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.intellij.codeInsight.template.zencoding;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class OperationToken extends Token {
|
||||
public class OperationToken extends Token {
|
||||
private final char mySign;
|
||||
|
||||
OperationToken(char sign) {
|
||||
@@ -28,4 +28,9 @@ class OperationToken extends Token {
|
||||
public char getSign() {
|
||||
return mySign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Character.toString(mySign);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,9 @@ public class TemplateToken extends Token {
|
||||
public TemplateImpl getTemplate() {
|
||||
return myTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TEMPLATE";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ package com.intellij.codeInsight.template.zencoding;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class Token {
|
||||
public class Token {
|
||||
}
|
||||
|
||||
+2
-3
@@ -304,7 +304,6 @@ class XmlZenCodingInterpreter {
|
||||
return new XmlZenCodingFilterImpl().buildAttributesString(attribute2value, numberInIteration);
|
||||
}
|
||||
|
||||
|
||||
private static void invokeTemplate(TemplateToken token,
|
||||
final CustomTemplateCallback callback,
|
||||
final int numberInIteration,
|
||||
@@ -372,7 +371,7 @@ class XmlZenCodingInterpreter {
|
||||
return new XmlZenCodingFilterImpl().toString(tag, context);
|
||||
}
|
||||
|
||||
private static void fail() {
|
||||
LOG.error("Input string was checked incorrectly during isApplicable() invokation");
|
||||
private void fail() {
|
||||
LOG.error("Input string was checked incorrectly during isApplicable() invokation: " + myTokens.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,15 +336,13 @@ public class XmlZenCodingTemplate extends ZenCodingTemplate {
|
||||
int lineStart = editor.getDocument().getLineStartOffset(line);
|
||||
int elementStart;
|
||||
do {
|
||||
elementStart = element != null ? element.getTextRange().getStartOffset() : 0;
|
||||
elementStart = element.getTextRange().getStartOffset();
|
||||
int startOffset = elementStart > lineStart ? elementStart : lineStart;
|
||||
String key = computeKey(editor, startOffset);
|
||||
if (checkTemplateKey(key, callback)) {
|
||||
return key;
|
||||
}
|
||||
if (element != null) {
|
||||
element = element.getParent();
|
||||
}
|
||||
element = element.getParent();
|
||||
}
|
||||
while (element != null && elementStart > lineStart);
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user