Merge remote-tracking branch 'origin/master' into SDK_AT_HEAD
diff --git a/angular_analyzer_plugin/lib/src/angular_driver.dart b/angular_analyzer_plugin/lib/src/angular_driver.dart
index 2f3a3a6..e590c71 100644
--- a/angular_analyzer_plugin/lib/src/angular_driver.dart
+++ b/angular_analyzer_plugin/lib/src/angular_driver.dart
@@ -382,25 +382,24 @@
 
   Future<StandardAngular> getStandardAngular() async {
     if (standardAngular == null) {
-      final source = _sourceFactory.resolveUri(
-          null,
-          _hasAngularImported
-              ? "package:angular/angular.dart"
-              : "package:angular2/angular2.dart");
+      final source =
+          _sourceFactory.resolveUri(null, "package:angular/angular.dart");
 
       if (source == null) {
         return standardAngular;
       }
 
-      final securitySource = _sourceFactory.resolveUri(
-          null,
-          _hasAngularImported
-              ? "package:angular/security.dart"
-              : "package:angular2/security.dart");
+      final securitySource =
+          _sourceFactory.resolveUri(null, "package:angular/security.dart");
+      final protoSecuritySource = _sourceFactory.resolveUri(
+          null, 'package:webutil.html.types.proto/html.pb.dart');
 
       standardAngular = new StandardAngular.fromAnalysis(
-          await dartDriver.getResult(source.fullName),
-          await dartDriver.getResult(securitySource.fullName));
+          angularResult: await dartDriver.getResult(source.fullName),
+          securityResult: await dartDriver.getResult(securitySource.fullName),
+          protoSecurityResult: protoSecuritySource == null
+              ? null
+              : await dartDriver.getResult(protoSecuritySource.fullName));
     }
 
     return standardAngular;
diff --git a/angular_analyzer_plugin/lib/src/resolver.dart b/angular_analyzer_plugin/lib/src/resolver.dart
index 86df668..bdcd056 100644
--- a/angular_analyzer_plugin/lib/src/resolver.dart
+++ b/angular_analyzer_plugin/lib/src/resolver.dart
@@ -1532,7 +1532,7 @@
         attribute.valueOffset,
         attribute.value.length,
         AngularWarningCode.UNSAFE_BINDING,
-        [securityContext.safeType.toString()]));
+        [securityContext.safeTypes.join(' or ')]));
     return false;
   }
 
@@ -1854,7 +1854,8 @@
       final securityContext = input.securityContext;
 
       if (securityContext != null) {
-        if (typeSystem.isAssignableTo(attrType, securityContext.safeType)) {
+        if (securityContext.safeTypes
+            .any((safeType) => typeSystem.isAssignableTo(attrType, safeType))) {
           return;
         } else if (!securityContext.sanitizationAvailable) {
           errorListener.onError(new AnalysisError(
@@ -1862,7 +1863,7 @@
               attr.valueOffset,
               attr.value.length,
               AngularWarningCode.UNSAFE_BINDING,
-              [securityContext.safeType.toString()]));
+              [securityContext.safeTypes.join(' or ')]));
           return;
         }
       }
diff --git a/angular_analyzer_plugin/lib/src/standard_components.dart b/angular_analyzer_plugin/lib/src/standard_components.dart
index bea9514..5e5132e 100644
--- a/angular_analyzer_plugin/lib/src/standard_components.dart
+++ b/angular_analyzer_plugin/lib/src/standard_components.dart
@@ -234,10 +234,10 @@
 }
 
 class SecurityContext {
-  final DartType safeType;
+  final List<DartType> safeTypes;
   final bool sanitizationAvailable;
 
-  SecurityContext(this.safeType, {this.sanitizationAvailable = true});
+  SecurityContext(this.safeTypes, {this.sanitizationAvailable = true});
 }
 
 class SecuritySchema {
@@ -322,23 +322,29 @@
       this.securitySchema});
 
   factory StandardAngular.fromAnalysis(
-      ResolvedUnitResult ngResult, ResolvedUnitResult securityResult) {
-    final ng = ngResult.unit.element.library.exportNamespace;
+      {ResolvedUnitResult angularResult,
+      ResolvedUnitResult securityResult,
+      ResolvedUnitResult protoSecurityResult}) {
+    final ng = angularResult.unit.element.library.exportNamespace;
     final security = securityResult.unit.element.library.exportNamespace;
+    final protoSecurity = protoSecurityResult == null
+        ? null
+        : protoSecurityResult.unit.element.library.exportNamespace;
 
-    SecurityContext makeSecurityContext(Element element,
-            {bool sanitizationAvailable: true}) =>
-        new SecurityContext((element as ClassElement)?.type,
-            sanitizationAvailable: sanitizationAvailable);
+    List<DartType> safeTypes(String id) =>
+        [security.get('Safe$id'), protoSecurity?.get('Safe${id}Proto')]
+            .whereType<ClassElement>()
+            .map((e) => e?.type)
+            .where((e) => e != null)
+            .toList();
 
     final securitySchema = new SecuritySchema(
-        htmlSecurityContext: makeSecurityContext(security.get('SafeHtml')),
-        urlSecurityContext: makeSecurityContext(security.get('SafeUrl')),
-        styleSecurityContext: makeSecurityContext(security.get('SafeStyle')),
-        scriptSecurityContext: makeSecurityContext(security.get('SafeScript'),
-            sanitizationAvailable: false),
-        resourceUrlSecurityContext: makeSecurityContext(
-            security.get('SafeResourceUrl'),
+        htmlSecurityContext: SecurityContext(safeTypes('Html')),
+        urlSecurityContext: SecurityContext(safeTypes('Url')),
+        styleSecurityContext: SecurityContext(safeTypes('Style')),
+        scriptSecurityContext:
+            SecurityContext(safeTypes('Script'), sanitizationAvailable: false),
+        resourceUrlSecurityContext: SecurityContext(safeTypes('ResourceUrl'),
             sanitizationAvailable: false));
 
     return new StandardAngular(
diff --git a/angular_analyzer_plugin/test/angular_driver_test.dart b/angular_analyzer_plugin/test/angular_driver_test.dart
index d406286..52a0494d1c 100644
--- a/angular_analyzer_plugin/test/angular_driver_test.dart
+++ b/angular_analyzer_plugin/test/angular_driver_test.dart
@@ -131,37 +131,37 @@
 
     final imgSrcSecurity = ng.securitySchema.lookup('img', 'src');
     expect(imgSrcSecurity, isNotNull);
-    expect(imgSrcSecurity.safeType.toString(), 'SafeUrl');
+    expect(imgSrcSecurity.safeTypes[0].toString(), 'SafeUrl');
     expect(imgSrcSecurity.sanitizationAvailable, true);
 
     final aHrefSecurity = ng.securitySchema.lookup('a', 'href');
     expect(aHrefSecurity, isNotNull);
-    expect(aHrefSecurity.safeType.toString(), 'SafeUrl');
+    expect(aHrefSecurity.safeTypes[0].toString(), 'SafeUrl');
     expect(aHrefSecurity.sanitizationAvailable, true);
 
     final innerHtmlSecurity = ng.securitySchema.lookupGlobal('innerHTML');
     expect(innerHtmlSecurity, isNotNull);
-    expect(innerHtmlSecurity.safeType.toString(), 'SafeHtml');
+    expect(innerHtmlSecurity.safeTypes[0].toString(), 'SafeHtml');
     expect(innerHtmlSecurity.sanitizationAvailable, true);
 
     final iframeSrcdocSecurity = ng.securitySchema.lookup('iframe', 'srcdoc');
     expect(iframeSrcdocSecurity, isNotNull);
-    expect(iframeSrcdocSecurity.safeType.toString(), 'SafeHtml');
+    expect(iframeSrcdocSecurity.safeTypes[0].toString(), 'SafeHtml');
     expect(iframeSrcdocSecurity.sanitizationAvailable, true);
 
     final styleSecurity = ng.securitySchema.lookupGlobal('style');
     expect(styleSecurity, isNotNull);
-    expect(styleSecurity.safeType.toString(), 'SafeStyle');
+    expect(styleSecurity.safeTypes[0].toString(), 'SafeStyle');
     expect(styleSecurity.sanitizationAvailable, true);
 
     final iframeSrcSecurity = ng.securitySchema.lookup('iframe', 'src');
     expect(iframeSrcSecurity, isNotNull);
-    expect(iframeSrcSecurity.safeType.toString(), 'SafeResourceUrl');
+    expect(iframeSrcSecurity.safeTypes[0].toString(), 'SafeResourceUrl');
     expect(iframeSrcSecurity.sanitizationAvailable, false);
 
     final scriptSrcSecurity = ng.securitySchema.lookup('script', 'src');
     expect(scriptSrcSecurity, isNotNull);
-    expect(scriptSrcSecurity.safeType.toString(), 'SafeResourceUrl');
+    expect(scriptSrcSecurity.safeTypes[0].toString(), 'SafeResourceUrl');
     expect(scriptSrcSecurity.sanitizationAvailable, false);
   }
 }
@@ -192,7 +192,7 @@
       expect(input.setter, isNotNull);
       expect(input.setterType.toString(), equals('String'));
       expect(input.securityContext, isNotNull);
-      expect(input.securityContext.safeType.toString(), equals('SafeHtml'));
+      expect(input.securityContext.safeTypes[0].toString(), equals('SafeHtml'));
       expect(input.securityContext.sanitizationAvailable, equals(true));
     }
   }
@@ -283,7 +283,8 @@
         expect(input.setter, isNotNull);
         expect(input.setterType.toString(), equals("String"));
         expect(input.securityContext, isNotNull);
-        expect(input.securityContext.safeType.toString(), equals('SafeUrl'));
+        expect(
+            input.securityContext.safeTypes[0].toString(), equals('SafeUrl'));
         expect(input.securityContext.sanitizationAvailable, equals(true));
       }
       expect(outputElements, hasLength(0));
@@ -319,7 +320,7 @@
         expect(input.setter, isNotNull);
         expect(input.setterType.toString(), equals("String"));
         expect(input.securityContext, isNotNull);
-        expect(input.securityContext.safeType.toString(),
+        expect(input.securityContext.safeTypes[0].toString(),
             equals('SafeResourceUrl'));
         expect(input.securityContext.sanitizationAvailable, equals(false));
       }