[java] correct highlighting of JVM agent manifest headers (IDEA-147979)

This commit is contained in:
Roman Shevchenko
2015-11-16 11:44:01 +01:00
parent 70290391f9
commit a53a760b88
5 changed files with 53 additions and 11 deletions
@@ -5,6 +5,8 @@ manifest.header.expected=Header expected
header.name.invalid=Invalid header name
header.reference.invalid=Invalid reference
header.main.class.invalid=Invalid main class
header.pre-main.class.invalid=Invalid pre-main class
header.agent.class.invalid=Invalid agent class
inspection.group=Manifest
inspection.newline.message=Manifest file doesn't end with a final newline
@@ -23,9 +23,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiReference;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
@@ -38,6 +36,10 @@ import org.jetbrains.lang.manifest.psi.HeaderValue;
import org.jetbrains.lang.manifest.psi.HeaderValuePart;
public class ClassReferenceParser extends StandardHeaderParser {
public static final String MAIN_CLASS = "Main-Class";
public static final String PREMAIN_CLASS = "Premain-Class";
public static final String AGENT_CLASS = "Agent-Class";
public static final HeaderParser INSTANCE = new ClassReferenceParser();
@NotNull
@@ -86,11 +88,35 @@ public class ClassReferenceParser extends StandardHeaderParser {
}
protected boolean checkClass(@NotNull HeaderValuePart valuePart, @NotNull PsiClass aClass, @NotNull AnnotationHolder holder) {
if (!PsiMethodUtil.hasMainMethod(aClass)) {
String header = ((Header)valuePart.getParent()).getName();
if (header.equals(MAIN_CLASS) && !PsiMethodUtil.hasMainMethod(aClass)) {
holder.createErrorAnnotation(valuePart.getHighlightingRange(), ManifestBundle.message("header.main.class.invalid"));
return true;
}
if (header.equals(PREMAIN_CLASS) && !hasInstrumenterMethod(aClass, "premain")) {
holder.createErrorAnnotation(valuePart.getHighlightingRange(), ManifestBundle.message("header.pre-main.class.invalid"));
return true;
}
if (header.equals(AGENT_CLASS) && !hasInstrumenterMethod(aClass, "agentmain")) {
holder.createErrorAnnotation(valuePart.getHighlightingRange(), ManifestBundle.message("header.agent.class.invalid"));
return true;
}
return false;
}
}
private static boolean hasInstrumenterMethod(PsiClass aClass, String methodName) {
for (PsiMethod method : aClass.findMethodsByName(methodName, false)) {
if (PsiType.VOID.equals(method.getReturnType()) &&
method.hasModifierProperty(PsiModifier.PUBLIC) &&
method.hasModifierProperty(PsiModifier.STATIC)) {
return true;
}
}
return false;
}
}
@@ -43,7 +43,7 @@ public class StandardManifestHeaderParsers implements HeaderParserProvider {
myParsers.put("Created-By", StandardHeaderParser.INSTANCE);
myParsers.put("Signature-Version", StandardHeaderParser.INSTANCE);
myParsers.put("Class-Path", StandardHeaderParser.INSTANCE);
myParsers.put("Main-Class", ClassReferenceParser.INSTANCE);
myParsers.put(ClassReferenceParser.MAIN_CLASS, ClassReferenceParser.INSTANCE);
myParsers.put("Implementation-Title", StandardHeaderParser.INSTANCE);
myParsers.put("Implementation-Version", StandardHeaderParser.INSTANCE);
myParsers.put("Implementation-Vendor", StandardHeaderParser.INSTANCE);
@@ -59,8 +59,8 @@ public class StandardManifestHeaderParsers implements HeaderParserProvider {
myParsers.put("MD5-Digest", StandardHeaderParser.INSTANCE);
myParsers.put("SHA-Digest", StandardHeaderParser.INSTANCE);
myParsers.put("Magic", StandardHeaderParser.INSTANCE);
myParsers.put("Premain-Class", ClassReferenceParser.INSTANCE);
myParsers.put("Agent-Class", ClassReferenceParser.INSTANCE);
myParsers.put(ClassReferenceParser.PREMAIN_CLASS, ClassReferenceParser.INSTANCE);
myParsers.put(ClassReferenceParser.AGENT_CLASS, ClassReferenceParser.INSTANCE);
myParsers.put("Boot-Class-Path", StandardHeaderParser.INSTANCE);
myParsers.put("Can-Redefine-Classes", StandardHeaderParser.INSTANCE);
myParsers.put("Can-Retransform-Classes", StandardHeaderParser.INSTANCE);
@@ -72,4 +72,4 @@ public class StandardManifestHeaderParsers implements HeaderParserProvider {
public Map<String, HeaderParser> getHeaderParsers() {
return myParsers;
}
}
}
@@ -30,11 +30,23 @@ public class ManifestHighlightingTest extends LightCodeInsightFixtureTestCase {
doTest(
"Main-Class: <error descr=\"Invalid reference\"></error>\n" +
"Main-Class: <error descr=\"Cannot resolve class 'org.acme.Main'\">org.acme.Main</error>\n" +
"Main-Class: <error descr=\"Invalid main class\">java.lang.String</error>\n");
"Main-Class: <error descr=\"Invalid main class\">java.lang.String</error>\n" +
"Main-Class: pkg.C1\n");
}
public void testAgentHeaders() {
doTest(
"Premain-Class: <error descr=\"Invalid pre-main class\">pkg.C1</error>\n" +
"Premain-Class: pkg.C2\n" +
"Agent-Class: <error descr=\"Invalid agent class\">pkg.C1</error>\n" +
"Agent-Class: pkg.C3\n");
}
private void doTest(String text) {
myFixture.addClass("package pkg;\n\nclass C1 { public static void main(String... args) { } }");
myFixture.addClass("package pkg;\n\nclass C2 { public static void premain() { } }");
myFixture.addClass("package pkg;\n\nclass C3 { public static void agentmain() { } }");
myFixture.configureByText("MANIFEST.MF", text);
myFixture.checkHighlighting(true, false, false);
}
}
}
@@ -1,4 +1,5 @@
accessor
agentmain
aggregator
ajax
akka
@@ -431,6 +432,7 @@ postprocessor
pragma
prebuilt
prefetch
premain
prepend
prepended
prepends