Skip to content

Commit

Permalink
[mtouch] Show warnings when we can't find referenced assemblies. (#4511)
Browse files Browse the repository at this point in the history
* [mtouch] Show warnings when we can't find referenced assemblies.

This would have helped track down #4235.

* Improve MT0137 warning to indicate the type of the attribute causing the warning.
  • Loading branch information
rolfbjarne authored Jul 30, 2018
1 parent 69eb5cf commit fd05ba6
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 14 deletions.
2 changes: 2 additions & 0 deletions docs/website/mmp-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ Alternatively, enable the managed [linker](https://docs.microsoft.com/xamarin/ma

As a last-straw solution, use an older version of Xamarin.Mac that does not require these new SDKs to be present during the build process.

<!-- 0136 and 0137 used by mtouch -->

# MM1xxx: file copy / symlinks (project related)

### <a name="MM1034">MM1034: Could not create symlink '{file}' -> '{target}': error {number}
Expand Down
16 changes: 16 additions & 0 deletions docs/website/mtouch-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,22 @@ Alternatively, enable the managed [linker](https://docs.microsoft.com/en-us/xama

As a last-straw solution, use an older version of Xamarin.iOS that does not require these new SDKs to be present during the build process.

### <a name="MT0136"/>MT0136: Cannot find the assembly {assembly} referenced from {assembly}.

This warning occurs when an assembly passed to mtouch contains a reference to
another assembly that can't be found.

mtouch may in certain cases still find references at a later point, which
means that if the build otherwise succeeds, this warning can be ignored.

### <a name="MT0137"/>MT0137: Cannot find the assembly {assembly}, referenced by an attribute in {assembly}.

This warning occurs when an attribute contains a reference to another assembly
that can't be found.

mtouch may in certain cases still find references at a later point, which
means that if the build otherwise succeeds, this warning can be ignored.

# MT1xxx: Project related error messages

### MT10xx: Installer / mtouch
Expand Down
3 changes: 2 additions & 1 deletion tests/common/BundlerTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum I18N
abstract class BundlerTool : Tool
{
public const string None = "None";
public bool AlwaysShowOutput;

#pragma warning disable 0649 // Field 'X' is never assigned to, and will always have its default value Y
// These map directly to mtouch/mmp options
Expand Down Expand Up @@ -306,7 +307,7 @@ public void CreateTemporaryCacheDirectory ()

public virtual int Execute ()
{
return Execute (ToolArguments, always_show_output: Verbosity > 0);
return Execute (ToolArguments, always_show_output: Verbosity > 0 || AlwaysShowOutput);
}

public virtual void AssertExecute (string message = null)
Expand Down
61 changes: 61 additions & 0 deletions tests/mtouch/MTouch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,67 @@ public void MT0132 ()
}
}

[Test]
public void MT0136 ()
{
using (var mtouch = new MTouchTool ()) {
var tmpdir = mtouch.CreateTemporaryDirectory ();
mtouch.CreateTemporaryCacheDirectory ();

var codeDll = @"public class A {}";
var codeExe = @"public class B : A {}";

var dllPath = CompileTestAppLibrary (tmpdir, codeDll, profile: Profile.iOS, appName: "A");

mtouch.CreateTemporaryApp (extraCode: codeExe, extraArg: $"-r:{StringUtils.Quote (dllPath)}");
mtouch.Debug = false;
mtouch.Linker = MTouchLinker.DontLink;
File.Delete (dllPath);
mtouch.AssertExecuteFailure (MTouchAction.BuildSim, "build");
mtouch.AssertWarningPattern (136, "Cannot find the assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' referenced from '.*/testApp.exe'.");
mtouch.AssertError (2002, "Failed to resolve assembly: 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'");
mtouch.AssertErrorCount (1);
mtouch.AssertWarningCount (1);
}
}

[Test]
public void MT0137 ()
{
using (var mtouch = new MTouchTool ()) {
var tmpdir = mtouch.CreateTemporaryDirectory ();
mtouch.CreateTemporaryCacheDirectory ();

var codeDll = @"public class A {}";
var codeExe = @"
[assembly: MyCustomAttribute (typeof (A))]
public class MyCustomAttribute : System.Attribute
{
public MyCustomAttribute (System.Type type) {}
}
[System.Diagnostics.DebuggerTypeProxyAttribute (typeof (A))]
public class B
{
}
";
var codeExeFile = Path.Combine (tmpdir, "extraCode.cs");
File.WriteAllText (codeExeFile, codeExe);
var dllPath = CompileTestAppLibrary (tmpdir, codeDll, profile: Profile.iOS, appName: "A");

mtouch.CreateTemporaryApp (extraArg: $"-r:{StringUtils.Quote (dllPath)} {StringUtils.Quote (codeExeFile)}");
mtouch.Debug = false;
mtouch.Linker = MTouchLinker.DontLink;
File.Delete (dllPath);
mtouch.AlwaysShowOutput = true;
mtouch.AssertExecute (MTouchAction.BuildSim, "build");
mtouch.AssertWarning (137, "Cannot find the assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null', referenced by a MyCustomAttribute attribute in 'testApp.exe'.");
mtouch.AssertWarning (137, "Cannot find the assembly 'A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null', referenced by a System.Diagnostics.DebuggerTypeProxyAttribute attribute in 'testApp.exe'.");
mtouch.AssertWarningCount (2);
}
}

[Test]
[TestCase ("all")]
[TestCase ("-all")]
Expand Down
31 changes: 18 additions & 13 deletions tools/mtouch/Target.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ void ComputeListOfAssemblies (HashSet<string> assemblies, AssemblyDefinition ass
}

var reference_assembly = ManifestResolver.Resolve (reference);
if (reference_assembly == null) {
ErrorHelper.Warning (136, "Cannot find the assembly '{0}' referenced from '{1}'.", reference.FullName, main.FileName);
continue;
}
ComputeListOfAssemblies (assemblies, reference_assembly, exceptions);
}

Expand All @@ -402,46 +406,47 @@ void ComputeListOfAssemblies (HashSet<string> assemblies, AssemblyDefinition ass
// Custom Attribute metadata can include references to other assemblies, e.g. [X (typeof (Y)],
// but it is not reflected in AssemblyReferences :-( ref: #37611
// so we must scan every custom attribute to look for System.Type
GetCustomAttributeReferences (assembly, assemblies, exceptions);
GetCustomAttributeReferences (main, assemblies, exceptions);
if (main.HasTypes) {
foreach (var ca in main.GetCustomAttributes ())
GetCustomAttributeReferences (ca, assemblies, exceptions);
}
GetCustomAttributeReferences (main, main, assemblies, exceptions);
foreach (var ca in main.GetCustomAttributes ())
GetCustomAttributeReferences (main, ca, assemblies, exceptions);
}

void GetCustomAttributeReferences (ICustomAttributeProvider cap, HashSet<string> assemblies, List<Exception> exceptions)
void GetCustomAttributeReferences (ModuleDefinition main, ICustomAttributeProvider cap, HashSet<string> assemblies, List<Exception> exceptions)
{
if (!cap.HasCustomAttributes)
return;
foreach (var ca in cap.CustomAttributes)
GetCustomAttributeReferences (ca, assemblies, exceptions);
GetCustomAttributeReferences (main, ca, assemblies, exceptions);
}

void GetCustomAttributeReferences (CustomAttribute ca, HashSet<string> assemblies, List<Exception> exceptions)
void GetCustomAttributeReferences (ModuleDefinition main, CustomAttribute ca, HashSet<string> assemblies, List<Exception> exceptions)
{
if (ca.HasConstructorArguments) {
foreach (var arg in ca.ConstructorArguments)
GetCustomAttributeArgumentReference (arg, assemblies, exceptions);
GetCustomAttributeArgumentReference (main, ca, arg, assemblies, exceptions);
}
if (ca.HasFields) {
foreach (var arg in ca.Fields)
GetCustomAttributeArgumentReference (arg.Argument, assemblies, exceptions);
GetCustomAttributeArgumentReference (main, ca, arg.Argument, assemblies, exceptions);
}
if (ca.HasProperties) {
foreach (var arg in ca.Properties)
GetCustomAttributeArgumentReference (arg.Argument, assemblies, exceptions);
GetCustomAttributeArgumentReference (main, ca, arg.Argument, assemblies, exceptions);
}
}

void GetCustomAttributeArgumentReference (CustomAttributeArgument arg, HashSet<string> assemblies, List<Exception> exceptions)
void GetCustomAttributeArgumentReference (ModuleDefinition main, CustomAttribute ca, CustomAttributeArgument arg, HashSet<string> assemblies, List<Exception> exceptions)
{
if (!arg.Type.Is ("System", "Type"))
return;
var ar = (arg.Value as TypeReference)?.Scope as AssemblyNameReference;
if (ar == null)
return;
var reference_assembly = ManifestResolver.Resolve (ar);
if (reference_assembly == null) {
ErrorHelper.Warning (137, "Cannot find the assembly '{0}', referenced by a {2} attribute in '{1}'.", ar.FullName, main.Name, ca.AttributeType.FullName);
return;
}
ComputeListOfAssemblies (assemblies, reference_assembly, exceptions);
}

Expand Down

1 comment on commit fd05ba6

@xamarin-release-manager
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 Jenkins job (on internal Jenkins) failed in stage 'Test run' 🔥 : hudson.AbortException: script returned exit code 2

Build succeeded
API Diff (from stable)
ℹ️ API Diff (from PR only) (please review changes)
Generator Diff (only version changes)
🔥 Test run failed 🔥

Test results

2 tests failed, 0 tests skipped, 223 tests passed.

Failed tests

  • System.Core/watchOS - simulator/Debug: Failed
  • MTouch tests/NUnit: Failed (Execution failed with exit code 1)

Please sign in to comment.