Skip to content

Commit

Permalink
Handle MSBuild-style warnings (Prefix0000)
Browse files Browse the repository at this point in the history
  • Loading branch information
AliveDevil committed Jul 30, 2024
1 parent ff81eaf commit 551de52
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 278 deletions.
8 changes: 4 additions & 4 deletions src/IKVM.Tools.Importer/CompilerClassLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3406,8 +3406,8 @@ sealed class CompilerOptions
internal uint fileAlignment;
internal bool highentropyva;
internal List<CompilerClassLoader> sharedclassloader; // should *not* be deep copied in Copy(), because we want the list of all compilers that share a class loader
internal Dictionary<string, string> suppressWarnings = new Dictionary<string, string>();
internal Dictionary<string, string> errorWarnings = new Dictionary<string, string>(); // treat specific warnings as errors
internal HashSet<string> suppressWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
internal HashSet<string> errorWarnings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
internal bool warnaserror; // treat all warnings as errors
internal FileInfo writeSuppressWarningsFile;
internal List<string> proxies = new List<string>();
Expand All @@ -3429,8 +3429,8 @@ internal CompilerOptions Copy()
{
copy.externalResources = new Dictionary<string, string>(externalResources);
}
copy.suppressWarnings = new Dictionary<string, string>(suppressWarnings);
copy.errorWarnings = new Dictionary<string, string>(errorWarnings);
copy.suppressWarnings = new(suppressWarnings, StringComparer.OrdinalIgnoreCase);
copy.errorWarnings = new(errorWarnings, StringComparer.OrdinalIgnoreCase);
return copy;
}

Expand Down
75 changes: 46 additions & 29 deletions src/IKVM.Tools.Importer/IkvmImporterInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -748,31 +748,15 @@ void ContinueParseCommandLine(RuntimeContext context, StaticCompiler compiler, I
}
else if (s.StartsWith("-nowarn:"))
{
foreach (var w in s.Substring(8).Split(','))
{
// lame way to chop off the leading zeroes
string ws = w;
while (ws.StartsWith("0"))
ws = ws.Substring(1);

options.suppressWarnings[ws] = ws;
}
HandleWarnArg(options.suppressWarnings, s.Substring(8));
}
else if (s == "-warnaserror")
{
options.warnaserror = true;
}
else if (s.StartsWith("-warnaserror:"))
{
foreach (string w in s.Substring(13).Split(','))
{
// lame way to chop off the leading zeroes
string ws = w;
while (ws.StartsWith("0"))
ws = ws.Substring(1);

options.errorWarnings[ws] = ws;
}
HandleWarnArg(options.errorWarnings, s.Substring(8));
}
else if (s.StartsWith("-runtime:"))
{
Expand Down Expand Up @@ -1449,20 +1433,18 @@ internal static void IssueMessage(StaticCompiler compiler, CompilerOptions optio
return;
}

string key = ((int)msgId).ToString();
for (int i = 0; ; i++)
var msgIdKey = $"{(int)msgId}";
string key = msgIdKey;
foreach (var item in values)
{
if (options.suppressWarnings.ContainsKey(key))
if (options.suppressWarnings.Contains(key))
{
return;
}
if (i == values.Length)
{
break;
}
key += ":" + values[i];

key = $"{key}:{item}";
}
options.suppressWarnings.Add(key, key);
options.suppressWarnings.Add(key);
if (options.writeSuppressWarningsFile != null)
{
File.AppendAllText(options.writeSuppressWarningsFile.FullName, "-nowarn:" + key + Environment.NewLine);
Expand Down Expand Up @@ -1668,8 +1650,8 @@ internal static void IssueMessage(StaticCompiler compiler, CompilerOptions optio
}
bool error = msgId >= Message.StartErrors
|| (options.warnaserror && msgId >= Message.StartWarnings)
|| options.errorWarnings.ContainsKey(key)
|| options.errorWarnings.ContainsKey(((int)msgId).ToString());
|| options.errorWarnings.Contains(key)
|| options.errorWarnings.Contains(msgIdKey);
Console.Error.Write("{0} IKVMC{1:D4}: ", error ? "error" : msgId < Message.StartWarnings ? "note" : "warning", (int)msgId);
if (error && Message.StartWarnings <= msgId && msgId < Message.StartErrors)
{
Expand All @@ -1689,6 +1671,41 @@ internal static void IssueMessage(StaticCompiler compiler, CompilerOptions optio
}
}

internal static void HandleWarnArg(ICollection<string> target, string arg)
{
foreach (var w in arg.Split(','))
{
// Strip IKVMC prefix
int prefixStart = w.StartsWith("IKVMC", StringComparison.OrdinalIgnoreCase) ? 5 : 0;
int contextIndex = w.IndexOf(':', prefixStart);
string context = string.Empty;
string parse;
if(contextIndex != -1)
{
// context includes ':' separator
context = w.Substring(contextIndex);
parse = w.Substring(prefixStart, contextIndex - prefixStart);
}
else
{
parse = w.Substring(prefixStart);
}

if (!int.TryParse(parse, out var intResult))
{
if (!Enum.TryParse<Message>(parse, out var namedResult))
{
continue; // silently continue
}

// Warnings are handled as int.
intResult = (int)namedResult;
}

// Check IssueMessage
target.Add($"{intResult}{context}");
}
}
}

}
247 changes: 2 additions & 245 deletions src/IKVM.Tools.Importer/StaticCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ internal void IssueMissingTypeMessage(Type type)

internal void SuppressWarning(CompilerOptions options, Message message, string name)
{
options.suppressWarnings[(int)message + ":" + name] = null;
options.suppressWarnings.Add($"{(int)message}:{name}");
}

internal void IssueMessage(Message msgId, params string[] values)
Expand All @@ -240,250 +240,7 @@ internal void IssueMessage(Message msgId, params string[] values)

internal void IssueMessage(CompilerOptions options, Message msgId, params string[] values)
{
if (errorCount != 0 && msgId < Message.StartErrors && !options.warnaserror)
{
// don't display any warnings after we've emitted an error message
return;
}

string key = ((int)msgId).ToString();
for (int i = 0; ; i++)
{
if (options.suppressWarnings.ContainsKey(key))
{
return;
}
if (i == values.Length)
{
break;
}
key += ":" + values[i];
}
options.suppressWarnings.Add(key, key);
if (options.writeSuppressWarningsFile != null)
{
File.AppendAllText(options.writeSuppressWarningsFile.FullName, "-nowarn:" + key + Environment.NewLine);
}
string msg;
switch (msgId)
{
case Message.MainMethodFound:
msg = "Found main method in class \"{0}\"";
break;
case Message.OutputFileIs:
msg = "Output file is \"{0}\"";
break;
case Message.AutoAddRef:
msg = "Automatically adding reference to \"{0}\"";
break;
case Message.MainMethodFromManifest:
msg = "Using main class \"{0}\" based on jar manifest";
break;
case Message.ClassNotFound:
msg = "Class \"{0}\" not found";
break;
case Message.ClassFormatError:
msg = "Unable to compile class \"{0}\"" + Environment.NewLine +
" (class format error \"{1}\")";
break;
case Message.DuplicateClassName:
msg = "Duplicate class name: \"{0}\"";
break;
case Message.IllegalAccessError:
msg = "Unable to compile class \"{0}\"" + Environment.NewLine +
" (illegal access error \"{1}\")";
break;
case Message.VerificationError:
msg = "Unable to compile class \"{0}\"" + Environment.NewLine +
" (verification error \"{1}\")";
break;
case Message.NoClassDefFoundError:
msg = "Unable to compile class \"{0}\"" + Environment.NewLine +
" (missing class \"{1}\")";
break;
case Message.GenericUnableToCompileError:
msg = "Unable to compile class \"{0}\"" + Environment.NewLine +
" (\"{1}\": \"{2}\")";
break;
case Message.DuplicateResourceName:
msg = "Skipping resource (name clash): \"{0}\"";
break;
case Message.SkippingReferencedClass:
msg = "Skipping class: \"{0}\"" + Environment.NewLine +
" (class is already available in referenced assembly \"{1}\")";
break;
case Message.NoJniRuntime:
msg = "Unable to load runtime JNI assembly";
break;
case Message.EmittedNoClassDefFoundError:
msg = "Emitted java.lang.NoClassDefFoundError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedIllegalAccessError:
msg = "Emitted java.lang.IllegalAccessError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedInstantiationError:
msg = "Emitted java.lang.InstantiationError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedIncompatibleClassChangeError:
msg = "Emitted java.lang.IncompatibleClassChangeError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedNoSuchFieldError:
msg = "Emitted java.lang.NoSuchFieldError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedAbstractMethodError:
msg = "Emitted java.lang.AbstractMethodError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedNoSuchMethodError:
msg = "Emitted java.lang.NoSuchMethodError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedLinkageError:
msg = "Emitted java.lang.LinkageError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedVerificationError:
msg = "Emitted java.lang.VerificationError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.EmittedClassFormatError:
msg = "Emitted java.lang.ClassFormatError in \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.InvalidCustomAttribute:
msg = "Error emitting \"{0}\" custom attribute" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.IgnoredCustomAttribute:
msg = "Custom attribute \"{0}\" was ignored" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.AssumeAssemblyVersionMatch:
msg = "Assuming assembly reference \"{0}\" matches \"{1}\", you may need to supply runtime policy";
break;
case Message.InvalidDirectoryInLibOptionPath:
msg = "Directory \"{0}\" specified in -lib option is not valid";
break;
case Message.InvalidDirectoryInLibEnvironmentPath:
msg = "Directory \"{0}\" specified in LIB environment is not valid";
break;
case Message.LegacySearchRule:
msg = "Found assembly \"{0}\" using legacy search rule, please append '.dll' to the reference";
break;
case Message.AssemblyLocationIgnored:
msg = "Assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\"";
break;
case Message.InterfaceMethodCantBeInternal:
msg = "Ignoring @ikvm.lang.Internal annotation on interface method" + Environment.NewLine +
" (\"{0}.{1}{2}\")";
break;
case Message.NonPrimaryAssemblyReference:
msg = "Referenced assembly \"{0}\" is not the primary assembly of a shared class loader group, please reference primary assembly \"{1}\" instead";
break;
case Message.MissingType:
msg = "Reference to type \"{0}\" claims it is defined in \"{1}\", but it could not be found";
break;
case Message.MissingReference:
msg = "The type '{0}' is defined in an assembly that is not referenced. You must add a reference to assembly '{1}'";
break;
case Message.DuplicateAssemblyReference:
msg = "Duplicate assembly reference \"{0}\"";
break;
case Message.UnableToResolveType:
msg = "Reference in \"{0}\" to type \"{1}\" claims it is defined in \"{2}\", but it could not be found";
break;
case Message.StubsAreDeprecated:
msg = "Compiling stubs is deprecated. Please add a reference to assembly \"{0}\" instead.";
break;
case Message.WrongClassName:
msg = "Unable to compile \"{0}\" (wrong name: \"{1}\")";
break;
case Message.ReflectionCallerClassRequiresCallerID:
msg = "Reflection.getCallerClass() called from non-CallerID method" + Environment.NewLine +
" (\"{0}.{1}{2}\")";
break;
case Message.LegacyAssemblyAttributesFound:
msg = "Legacy assembly attributes container found. Please use the -assemblyattributes:<file> option.";
break;
case Message.UnableToCreateLambdaFactory:
msg = "Unable to create static lambda factory.";
break;
case Message.UnableToCreateProxy:
msg = "Unable to create proxy \"{0}\"" + Environment.NewLine +
" (\"{1}\")";
break;
case Message.DuplicateProxy:
msg = "Duplicate proxy \"{0}\"";
break;
case Message.MapXmlUnableToResolveOpCode:
msg = "Unable to resolve opcode in remap file: {0}";
break;
case Message.MapXmlError:
msg = "Error in remap file: {0}";
break;
case Message.InputFileNotFound:
msg = "Source file '{0}' not found";
break;
case Message.UnknownFileType:
msg = "Unknown file type: {0}";
break;
case Message.UnknownElementInMapFile:
msg = "Unknown element {0} in remap file, line {1}, column {2}";
break;
case Message.UnknownAttributeInMapFile:
msg = "Unknown attribute {0} in remap file, line {1}, column {2}";
break;
case Message.InvalidMemberNameInMapFile:
msg = "Invalid {0} name '{1}' in remap file in class {2}";
break;
case Message.InvalidMemberSignatureInMapFile:
msg = "Invalid {0} signature '{3}' in remap file for {0} {1}.{2}";
break;
case Message.InvalidPropertyNameInMapFile:
msg = "Invalid property {0} name '{3}' in remap file for property {1}.{2}";
break;
case Message.InvalidPropertySignatureInMapFile:
msg = "Invalid property {0} signature '{3}' in remap file for property {1}.{2}";
break;
case Message.UnknownWarning:
msg = "{0}";
break;
case Message.CallerSensitiveOnUnsupportedMethod:
msg = "CallerSensitive annotation on unsupported method" + Environment.NewLine +
" (\"{0}.{1}{2}\")";
break;
case Message.RemappedTypeMissingDefaultInterfaceMethod:
msg = "{0} does not implement default interface method {1}";
break;
default:
throw new InvalidProgramException();
}
bool error = msgId >= Message.StartErrors
|| (options.warnaserror && msgId >= Message.StartWarnings)
|| options.errorWarnings.ContainsKey(key)
|| options.errorWarnings.ContainsKey(((int)msgId).ToString());
Console.Error.Write("{0} IKVMC{1:D4}: ", error ? "error" : msgId < Message.StartWarnings ? "note" : "warning", (int)msgId);
if (error && Message.StartWarnings <= msgId && msgId < Message.StartErrors)
{
Console.Error.Write("Warning as Error: ");
}
Console.Error.WriteLine(msg, values);
if (options != this.rootTarget && options.path != null)
{
Console.Error.WriteLine(" (in {0})", options.path);
}
if (error)
{
if (++errorCount == 100)
{
throw new FatalCompilerErrorException(Message.MaximumErrorCountReached);
}
}
IkvmImporterInternal.IssueMessage(this, options, msgId, values);
}

}
Expand Down

0 comments on commit 551de52

Please sign in to comment.